From 8b897879cd3925f701708e30710534aa5d0ae616 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 28 Nov 2009 23:37:56 +0000 Subject: [PATCH] pep8 cleanup in ui and op dirs, added popup to select pattern --- release/scripts/op/mesh_skin.py | 1170 +++++----- release/scripts/op/object.py | 44 +- release/scripts/op/presets.py | 16 +- release/scripts/op/uvcalc_smart_project.py | 2036 ++++++++--------- release/scripts/op/wm.py | 2 +- release/scripts/ui/properties_data_bone.py | 1 + release/scripts/ui/properties_material.py | 2 +- .../ui/properties_object_constraint.py | 1 + .../scripts/ui/properties_physics_cloth.py | 4 +- release/scripts/ui/properties_render.py | 6 +- release/scripts/ui/space_image.py | 8 +- release/scripts/ui/space_sequencer.py | 4 +- release/scripts/ui/space_text.py | 1 - release/scripts/ui/space_userpref.py | 2 +- release/scripts/ui/space_view3d.py | 110 +- release/scripts/ui/space_view3d_toolbar.py | 2 +- 16 files changed, 1702 insertions(+), 1707 deletions(-) diff --git a/release/scripts/op/mesh_skin.py b/release/scripts/op/mesh_skin.py index 63b5a44e901..5cf526cc23e 100644 --- a/release/scripts/op/mesh_skin.py +++ b/release/scripts/op/mesh_skin.py @@ -4,12 +4,12 @@ # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@ -29,620 +29,620 @@ from Mathutils import AngleBetweenVecs as _AngleBetweenVecs_ BIG_NUM = 1<<30 global CULL_METHOD -CULL_METHOD = 0 +CULL_METHOD = 0 def AngleBetweenVecs(a1,a2): - import math - try: - return math.degrees(_AngleBetweenVecs_(a1,a2)) - except: - return 180.0 + import math + try: + return math.degrees(_AngleBetweenVecs_(a1,a2)) + except: + return 180.0 class edge(object): - __slots__ = 'v1', 'v2', 'co1', 'co2', 'length', 'removed', 'match', 'cent', 'angle', 'next', 'prev', 'normal', 'fake' - def __init__(self, v1,v2): - self.v1 = v1 - self.v2 = v2 - co1, co2= v1.co, v2.co - self.co1= co1 - self.co2= co2 - - # uv1 uv2 vcol1 vcol2 # Add later - self.length = (co1 - co2).length - self.removed = 0 # Have we been culled from the eloop - self.match = None # The other edge were making a face with - - self.cent= MidpointVecs(co1, co2) - self.angle= 0.0 - self.fake= False + __slots__ = 'v1', 'v2', 'co1', 'co2', 'length', 'removed', 'match', 'cent', 'angle', 'next', 'prev', 'normal', 'fake' + def __init__(self, v1,v2): + self.v1 = v1 + self.v2 = v2 + co1, co2= v1.co, v2.co + self.co1= co1 + self.co2= co2 + + # uv1 uv2 vcol1 vcol2 # Add later + self.length = (co1 - co2).length + self.removed = 0 # Have we been culled from the eloop + self.match = None # The other edge were making a face with + + self.cent= MidpointVecs(co1, co2) + self.angle= 0.0 + self.fake= False class edgeLoop(object): - __slots__ = 'centre', 'edges', 'normal', 'closed', 'backup_edges' - def __init__(self, loop, me, closed): # Vert loop - # Use next and prev, nextDist, prevDist - - # Get Loops centre. - fac= len(loop) - verts = me.verts - self.centre= functools.reduce(lambda a,b: a+verts[b].co/fac, loop, Vector()) - - # Convert Vert loop to Edges. - self.edges = [edge(verts[loop[vIdx-1]], verts[loop[vIdx]]) for vIdx in range(len(loop))] - - if not closed: - self.edges[0].fake = True # fake edge option - - self.closed = closed - - - # Assign linked list - for eIdx in range(len(self.edges)-1): - self.edges[eIdx].next = self.edges[eIdx+1] - self.edges[eIdx].prev = self.edges[eIdx-1] - # Now last - self.edges[-1].next = self.edges[0] - self.edges[-1].prev = self.edges[-2] - - - - # GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP. - self.normal = Vector() - for e in self.edges: - n = (self.centre-e.co1).cross(self.centre-e.co2) - # Do we realy need tot normalize? - n.normalize() - self.normal += n - - # Generate the angle - va= e.cent - e.prev.cent - vb= e.next.cent - e.cent - - e.angle= AngleBetweenVecs(va, vb) - - # Blur the angles - #for e in self.edges: - # e.angle= (e.angle+e.next.angle)/2 - - # Blur the angles - #for e in self.edges: - # e.angle= (e.angle+e.prev.angle)/2 - - self.normal.normalize() - - # Generate a normal for each edge. - for e in self.edges: - - n1 = e.co1 - n2 = e.co2 - n3 = e.prev.co1 - - a = n1-n2 - b = n1-n3 - normal1 = a.cross(b) - normal1.normalize() - - n1 = e.co2 - n3 = e.next.co2 - n2 = e.co1 - - a = n1-n2 - b = n1-n3 - - normal2 = a.cross(b) - normal2.normalize() - - # Reuse normal1 var - normal1 += normal1 + normal2 - normal1.normalize() - - e.normal = normal1 - #print e.normal + __slots__ = 'centre', 'edges', 'normal', 'closed', 'backup_edges' + def __init__(self, loop, me, closed): # Vert loop + # Use next and prev, nextDist, prevDist + + # Get Loops centre. + fac= len(loop) + verts = me.verts + self.centre= functools.reduce(lambda a,b: a+verts[b].co/fac, loop, Vector()) + + # Convert Vert loop to Edges. + self.edges = [edge(verts[loop[vIdx-1]], verts[loop[vIdx]]) for vIdx in range(len(loop))] + + if not closed: + self.edges[0].fake = True # fake edge option + + self.closed = closed - - def backup(self): - # Keep a backup of the edges - self.backup_edges = self.edges[:] - - def restore(self): - self.edges = self.backup_edges[:] - for e in self.edges: - e.removed = 0 - - def reverse(self): - self.edges.reverse() - self.normal.negate() - - for e in self.edges: - e.normal.negate() - e.v1, e.v2 = e.v2, e.v1 - e.co1, e.co2 = e.co2, e.co1 - e.next, e.prev = e.prev, e.next - - - def removeSmallest(self, cullNum, otherLoopLen): - ''' - Removes N Smallest edges and backs up the loop, - this is so we can loop between 2 loops as if they are the same length, - backing up and restoring incase the loop needs to be skinned with another loop of a different length. - ''' - global CULL_METHOD - if CULL_METHOD == 1: # Shortest edge - eloopCopy = self.edges[:] - - # Length sort, smallest first - try: eloopCopy.sort(key = lambda e1: e1.length) - except: eloopCopy.sort(lambda e1, e2: cmp(e1.length, e2.length )) - - # Dont use atm - #eloopCopy.sort(lambda e1, e2: cmp(e1.angle*e1.length, e2.angle*e2.length)) # Length sort, smallest first - #eloopCopy.sort(lambda e1, e2: cmp(e1.angle, e2.angle)) # Length sort, smallest first - - remNum = 0 - for i, e in enumerate(eloopCopy): - if not e.fake: - e.removed = 1 - self.edges.remove( e ) # Remove from own list, still in linked list. - remNum += 1 - - if not remNum < cullNum: - break - - else: # CULL METHOD is even - - culled = 0 - - step = int(otherLoopLen / float(cullNum)) * 2 - - currentEdge = self.edges[0] - while culled < cullNum: - - # Get the shortest face in the next STEP - step_count= 0 - bestAng= 360.0 - smallestEdge= None - while step_count<=step or smallestEdge==None: - step_count+=1 - if not currentEdge.removed: # 0 or -1 will not be accepted - if currentEdge.angle 2: - return None - - vert_used[i] = True - - # do an edgeloop seek - if len(sbl) == 2: - contextVertLoop= [sbl[0], i, sbl[1]] # start the vert loop - vert_used[contextVertLoop[ 0]] = True - vert_used[contextVertLoop[-1]] = True - else: - contextVertLoop= [i, sbl[0]] - vert_used[contextVertLoop[ 1]] = True - - # Always seek up - ok = True - while ok: - ok = False - closed = False - sbl = vert_siblings[contextVertLoop[-1]] - if len(sbl) == 2: - next = sbl[not sbl.index( contextVertLoop[-2] )] - if vert_used[next]: - closed = True - # break - else: - contextVertLoop.append( next ) # get the vert that isnt the second last - vert_used[next] = True - ok = True - - # Seek down as long as the starting vert was not at the edge. - if not closed and len(vert_siblings[i]) == 2: - - ok = True - while ok: - ok = False - sbl = vert_siblings[contextVertLoop[0]] - if len(sbl) == 2: - next = sbl[not sbl.index( contextVertLoop[1] )] - if vert_used[next]: - closed = True - else: - contextVertLoop.insert(0, next) # get the vert that isnt the second last - vert_used[next] = True - ok = True - - mainVertLoops.append((contextVertLoop, closed)) - - - verts = me.verts - # convert from indicies to verts - # mainVertLoops = [([verts[i] for i in contextVertLoop], closed) for contextVertLoop, closed in mainVertLoops] - # print len(mainVertLoops) - return mainVertLoops - + ''' + return a list of vert loops, closed and open [(loop, closed)...] + ''' + + mainVertLoops = [] + # second method + tot = len(me.verts) + vert_siblings = [[] for i in range(tot)] + vert_used = [False] * tot + + for ed in selEdges: + i1, i2 = ed.key + vert_siblings[i1].append(i2) + vert_siblings[i2].append(i1) + + # find the first used vert and keep looping. + for i in range(tot): + if vert_siblings[i] and not vert_used[i]: + sbl = vert_siblings[i] # siblings + + if len(sbl) > 2: + return None + + vert_used[i] = True + + # do an edgeloop seek + if len(sbl) == 2: + contextVertLoop= [sbl[0], i, sbl[1]] # start the vert loop + vert_used[contextVertLoop[ 0]] = True + vert_used[contextVertLoop[-1]] = True + else: + contextVertLoop= [i, sbl[0]] + vert_used[contextVertLoop[ 1]] = True + + # Always seek up + ok = True + while ok: + ok = False + closed = False + sbl = vert_siblings[contextVertLoop[-1]] + if len(sbl) == 2: + next = sbl[not sbl.index( contextVertLoop[-2] )] + if vert_used[next]: + closed = True + # break + else: + contextVertLoop.append( next ) # get the vert that isnt the second last + vert_used[next] = True + ok = True + + # Seek down as long as the starting vert was not at the edge. + if not closed and len(vert_siblings[i]) == 2: + + ok = True + while ok: + ok = False + sbl = vert_siblings[contextVertLoop[0]] + if len(sbl) == 2: + next = sbl[not sbl.index( contextVertLoop[1] )] + if vert_used[next]: + closed = True + else: + contextVertLoop.insert(0, next) # get the vert that isnt the second last + vert_used[next] = True + ok = True + + mainVertLoops.append((contextVertLoop, closed)) + + + verts = me.verts + # convert from indicies to verts + # mainVertLoops = [([verts[i] for i in contextVertLoop], closed) for contextVertLoop, closed in mainVertLoops] + # print len(mainVertLoops) + return mainVertLoops + def skin2EdgeLoops(eloop1, eloop2, me, ob, MODE): - - new_faces= [] # - - # Make sure e1 loops is bigger then e2 - if len(eloop1.edges) != len(eloop2.edges): - if len(eloop1.edges) < len(eloop2.edges): - eloop1, eloop2 = eloop2, eloop1 - - eloop1.backup() # were about to cull faces - CULL_FACES = len(eloop1.edges) - len(eloop2.edges) - eloop1.removeSmallest(CULL_FACES, len(eloop1.edges)) - else: - CULL_FACES = 0 - # First make sure poly vert loops are in sync with eachother. - - # The vector allong which we are skinning. - skinVector = eloop1.centre - eloop2.centre - - loopDist = skinVector.length - - # IS THE LOOP FLIPPED, IF SO FLIP BACK. we keep it flipped, its ok, - if eloop1.closed or eloop2.closed: - angleBetweenLoopNormals = AngleBetweenVecs(eloop1.normal, eloop2.normal) - if angleBetweenLoopNormals > 90: - eloop2.reverse() - - DIR= eloop1.centre - eloop2.centre - - # if eloop2.closed: - bestEloopDist = BIG_NUM - bestOffset = 0 - # Loop rotation offset to test.1 - eLoopIdxs = list(range(len(eloop1.edges))) - for offset in range(len(eloop1.edges)): - totEloopDist = 0 # Measure this total distance for thsi loop. - - offsetIndexLs = eLoopIdxs[offset:] + eLoopIdxs[:offset] # Make offset index list - - - # e1Idx is always from 0uu to N, e2Idx is offset. - for e1Idx, e2Idx in enumerate(offsetIndexLs): - e1= eloop1.edges[e1Idx] - e2= eloop2.edges[e2Idx] - - - # Include fan connections in the measurement. - OK= True - while OK or e1.removed: - OK= False - - # Measure the vloop distance =============== - diff= ((e1.cent - e2.cent).length) #/ nangle1 - - ed_dir= e1.cent-e2.cent - a_diff= AngleBetweenVecs(DIR, ed_dir)/18 # 0 t0 18 - - totEloopDist += (diff * (1+a_diff)) / (1+loopDist) - - # Premeture break if where no better off - if totEloopDist > bestEloopDist: - break - - e1=e1.next - - if totEloopDist < bestEloopDist: - bestOffset = offset - bestEloopDist = totEloopDist - - # Modify V2 LS for Best offset - eloop2.edges = eloop2.edges[bestOffset:] + eloop2.edges[:bestOffset] - - else: - # Both are open loops, easier to calculate. - - - # Make sure the fake edges are at the start. - for i, edloop in enumerate((eloop1, eloop2)): - # print "LOOPO" - if edloop.edges[0].fake: - # alredy at the start - #print "A" - pass - elif edloop.edges[-1].fake: - # put the end at the start - edloop.edges.insert(0, edloop.edges.pop()) - #print "B" - - else: - for j, ed in enumerate(edloop.edges): - if ed.fake: - #print "C" - edloop.edges = edloop.edges = edloop.edges[j:] + edloop.edges[:j] - break - # print "DONE" - ed1, ed2 = eloop1.edges[0], eloop2.edges[0] - - if not ed1.fake or not ed2.fake: - raise "Error" - - # Find the join that isnt flipped (juts like detecting a bow-tie face) - a1 = (ed1.co1 - ed2.co1).length + (ed1.co2 - ed2.co2).length - a2 = (ed1.co1 - ed2.co2).length + (ed1.co2 - ed2.co1).length - - if a1 > a2: - eloop2.reverse() - # make the first edge the start edge still - eloop2.edges.insert(0, eloop2.edges.pop()) - - - - - for loopIdx in range(len(eloop2.edges)): - e1 = eloop1.edges[loopIdx] - e2 = eloop2.edges[loopIdx] - - # Remember the pairs for fan filling culled edges. - e1.match = e2; e2.match = e1 - - if not (e1.fake or e2.fake): - new_faces.append([e1.v1, e1.v2, e2.v2, e2.v1]) - - # FAN FILL MISSING FACES. - if CULL_FACES: - # Culled edges will be in eloop1. - FAN_FILLED_FACES = 0 - - contextEdge = eloop1.edges[0] # The larger of teh 2 - while FAN_FILLED_FACES < CULL_FACES: - while contextEdge.next.removed == 0: - contextEdge = contextEdge.next - - vertFanPivot = contextEdge.match.v2 - - while contextEdge.next.removed == 1: - #if not contextEdge.next.fake: - new_faces.append([contextEdge.next.v1, contextEdge.next.v2, vertFanPivot]) - - # Should we use another var?, this will work for now. - contextEdge.next.removed = 1 - - contextEdge = contextEdge.next - FAN_FILLED_FACES += 1 - - # may need to fan fill backwards 1 for non closed loops. - - eloop1.restore() # Add culled back into the list. - - return new_faces + new_faces= [] # + + # Make sure e1 loops is bigger then e2 + if len(eloop1.edges) != len(eloop2.edges): + if len(eloop1.edges) < len(eloop2.edges): + eloop1, eloop2 = eloop2, eloop1 + + eloop1.backup() # were about to cull faces + CULL_FACES = len(eloop1.edges) - len(eloop2.edges) + eloop1.removeSmallest(CULL_FACES, len(eloop1.edges)) + else: + CULL_FACES = 0 + # First make sure poly vert loops are in sync with eachother. + + # The vector allong which we are skinning. + skinVector = eloop1.centre - eloop2.centre + + loopDist = skinVector.length + + # IS THE LOOP FLIPPED, IF SO FLIP BACK. we keep it flipped, its ok, + if eloop1.closed or eloop2.closed: + angleBetweenLoopNormals = AngleBetweenVecs(eloop1.normal, eloop2.normal) + if angleBetweenLoopNormals > 90: + eloop2.reverse() + + + DIR= eloop1.centre - eloop2.centre + + # if eloop2.closed: + bestEloopDist = BIG_NUM + bestOffset = 0 + # Loop rotation offset to test.1 + eLoopIdxs = list(range(len(eloop1.edges))) + for offset in range(len(eloop1.edges)): + totEloopDist = 0 # Measure this total distance for thsi loop. + + offsetIndexLs = eLoopIdxs[offset:] + eLoopIdxs[:offset] # Make offset index list + + + # e1Idx is always from 0uu to N, e2Idx is offset. + for e1Idx, e2Idx in enumerate(offsetIndexLs): + e1= eloop1.edges[e1Idx] + e2= eloop2.edges[e2Idx] + + + # Include fan connections in the measurement. + OK= True + while OK or e1.removed: + OK= False + + # Measure the vloop distance =============== + diff= ((e1.cent - e2.cent).length) #/ nangle1 + + ed_dir= e1.cent-e2.cent + a_diff= AngleBetweenVecs(DIR, ed_dir)/18 # 0 t0 18 + + totEloopDist += (diff * (1+a_diff)) / (1+loopDist) + + # Premeture break if where no better off + if totEloopDist > bestEloopDist: + break + + e1=e1.next + + if totEloopDist < bestEloopDist: + bestOffset = offset + bestEloopDist = totEloopDist + + # Modify V2 LS for Best offset + eloop2.edges = eloop2.edges[bestOffset:] + eloop2.edges[:bestOffset] + + else: + # Both are open loops, easier to calculate. + + + # Make sure the fake edges are at the start. + for i, edloop in enumerate((eloop1, eloop2)): + # print "LOOPO" + if edloop.edges[0].fake: + # alredy at the start + #print "A" + pass + elif edloop.edges[-1].fake: + # put the end at the start + edloop.edges.insert(0, edloop.edges.pop()) + #print "B" + + else: + for j, ed in enumerate(edloop.edges): + if ed.fake: + #print "C" + edloop.edges = edloop.edges = edloop.edges[j:] + edloop.edges[:j] + break + # print "DONE" + ed1, ed2 = eloop1.edges[0], eloop2.edges[0] + + if not ed1.fake or not ed2.fake: + raise "Error" + + # Find the join that isnt flipped (juts like detecting a bow-tie face) + a1 = (ed1.co1 - ed2.co1).length + (ed1.co2 - ed2.co2).length + a2 = (ed1.co1 - ed2.co2).length + (ed1.co2 - ed2.co1).length + + if a1 > a2: + eloop2.reverse() + # make the first edge the start edge still + eloop2.edges.insert(0, eloop2.edges.pop()) + + + + + for loopIdx in range(len(eloop2.edges)): + e1 = eloop1.edges[loopIdx] + e2 = eloop2.edges[loopIdx] + + # Remember the pairs for fan filling culled edges. + e1.match = e2; e2.match = e1 + + if not (e1.fake or e2.fake): + new_faces.append([e1.v1, e1.v2, e2.v2, e2.v1]) + + # FAN FILL MISSING FACES. + if CULL_FACES: + # Culled edges will be in eloop1. + FAN_FILLED_FACES = 0 + + contextEdge = eloop1.edges[0] # The larger of teh 2 + while FAN_FILLED_FACES < CULL_FACES: + while contextEdge.next.removed == 0: + contextEdge = contextEdge.next + + vertFanPivot = contextEdge.match.v2 + + while contextEdge.next.removed == 1: + #if not contextEdge.next.fake: + new_faces.append([contextEdge.next.v1, contextEdge.next.v2, vertFanPivot]) + + # Should we use another var?, this will work for now. + contextEdge.next.removed = 1 + + contextEdge = contextEdge.next + FAN_FILLED_FACES += 1 + + # may need to fan fill backwards 1 for non closed loops. + + eloop1.restore() # Add culled back into the list. + + return new_faces def main(context): - global CULL_METHOD - - ob = context.object - - is_editmode = (ob.mode=='EDIT') - if is_editmode: bpy.ops.object.mode_set(mode='OBJECT', toggle=False) - if ob == None or ob.type != 'MESH': - raise Exception("BPyMessages.Error_NoMeshActive()") - return - - me = ob.data - - time1 = time.time() - selEdges = getSelectedEdges(context, me, ob) - vertLoops = getVertLoops(selEdges, me) # list of lists of edges. - if vertLoops == None: - raise Exception('Error%t|Selection includes verts that are a part of more then 1 loop') - if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False) - return - # print len(vertLoops) - - - if len(vertLoops) > 2: - choice = PupMenu('Loft '+str(len(vertLoops))+' edge loops%t|loop|segment') - if choice == -1: - if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False) - return - - elif len(vertLoops) < 2: - raise Exception('Error%t|No Vertloops found!') - if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False) - return - else: - choice = 2 - - - # The line below checks if any of the vert loops are differenyt in length. - if False in [len(v[0]) == len(vertLoops[0][0]) for v in vertLoops]: + global CULL_METHOD + + ob = context.object + + is_editmode = (ob.mode=='EDIT') + if is_editmode: bpy.ops.object.mode_set(mode='OBJECT', toggle=False) + if ob == None or ob.type != 'MESH': + raise Exception("BPyMessages.Error_NoMeshActive()") + return + + me = ob.data + + time1 = time.time() + selEdges = getSelectedEdges(context, me, ob) + vertLoops = getVertLoops(selEdges, me) # list of lists of edges. + if vertLoops == None: + raise Exception('Error%t|Selection includes verts that are a part of more then 1 loop') + if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False) + return + # print len(vertLoops) + + + if len(vertLoops) > 2: + choice = PupMenu('Loft '+str(len(vertLoops))+' edge loops%t|loop|segment') + if choice == -1: + if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False) + return + + elif len(vertLoops) < 2: + raise Exception('Error%t|No Vertloops found!') + if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False) + return + else: + choice = 2 + + + # The line below checks if any of the vert loops are differenyt in length. + if False in [len(v[0]) == len(vertLoops[0][0]) for v in vertLoops]: #XXX CULL_METHOD = PupMenu('Small to large edge loop distrobution method%t|remove edges evenly|remove smallest edges') #XXX if CULL_METHOD == -1: #XXX if is_editmode: Window.EditMode(1) #XXX return - CULL_METHOD = 1 # XXX FIXME - - - - - if CULL_METHOD ==1: # RESET CULL_METHOD - CULL_METHOD = 0 # shortest - else: - CULL_METHOD = 1 # even - - - time1 = time.time() - # Convert to special edge data. - edgeLoops = [] - for vloop, closed in vertLoops: - edgeLoops.append(edgeLoop(vloop, me, closed)) - - - # VERT LOOP ORDERING CODE - # "Build a worm" list - grow from Both ends - edgeOrderedList = [edgeLoops.pop()] - - # Find the closest. - bestSoFar = BIG_NUM - bestIdxSoFar = None - for edLoopIdx, edLoop in enumerate(edgeLoops): - l =(edgeOrderedList[-1].centre - edLoop.centre).length - if l < bestSoFar: - bestIdxSoFar = edLoopIdx - bestSoFar = l - - edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) ) - - # Now we have the 2 closest, append to either end- - # Find the closest. - while edgeLoops: - bestSoFar = BIG_NUM - bestIdxSoFar = None - first_or_last = 0 # Zero is first - for edLoopIdx, edLoop in enumerate(edgeLoops): - l1 =(edgeOrderedList[-1].centre - edLoop.centre).length - - if l1 < bestSoFar: - bestIdxSoFar = edLoopIdx - bestSoFar = l1 - first_or_last = 1 # last - - l2 =(edgeOrderedList[0].centre - edLoop.centre).length - if l2 < bestSoFar: - bestIdxSoFar = edLoopIdx - bestSoFar = l2 - first_or_last = 0 # last - - if first_or_last: # add closest Last - edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) ) - else: # Add closest First - edgeOrderedList.insert(0, edgeLoops.pop(bestIdxSoFar) ) # First - - faces = [] - - for i in range(len(edgeOrderedList)-1): - faces.extend( skin2EdgeLoops(edgeOrderedList[i], edgeOrderedList[i+1], me, ob, 0) ) - if choice == 1 and len(edgeOrderedList) > 2: # Loop - faces.extend( skin2EdgeLoops(edgeOrderedList[0], edgeOrderedList[-1], me, ob, 0) ) - - # REMOVE SELECTED FACES. - MESH_MODE= ob.mode - if MESH_MODE == 'EDGE' or MESH_MODE == 'VERTEX': pass - elif MESH_MODE == 'FACE': - try: me.faces.delete(1, [ f for f in me.faces if f.sel ]) - except: pass - - if 1: # 2.5 - mesh_faces_extend(me, faces, ob.active_material_index) - me.update(calc_edges=True) - else: - me.faces.extend(faces, smooth = True) - - print('\nSkin done in %.4f sec.' % (time.time()-time1)) - - if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False) + CULL_METHOD = 1 # XXX FIXME + + + + + if CULL_METHOD ==1: # RESET CULL_METHOD + CULL_METHOD = 0 # shortest + else: + CULL_METHOD = 1 # even + + + time1 = time.time() + # Convert to special edge data. + edgeLoops = [] + for vloop, closed in vertLoops: + edgeLoops.append(edgeLoop(vloop, me, closed)) + + + # VERT LOOP ORDERING CODE + # "Build a worm" list - grow from Both ends + edgeOrderedList = [edgeLoops.pop()] + + # Find the closest. + bestSoFar = BIG_NUM + bestIdxSoFar = None + for edLoopIdx, edLoop in enumerate(edgeLoops): + l =(edgeOrderedList[-1].centre - edLoop.centre).length + if l < bestSoFar: + bestIdxSoFar = edLoopIdx + bestSoFar = l + + edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) ) + + # Now we have the 2 closest, append to either end- + # Find the closest. + while edgeLoops: + bestSoFar = BIG_NUM + bestIdxSoFar = None + first_or_last = 0 # Zero is first + for edLoopIdx, edLoop in enumerate(edgeLoops): + l1 =(edgeOrderedList[-1].centre - edLoop.centre).length + + if l1 < bestSoFar: + bestIdxSoFar = edLoopIdx + bestSoFar = l1 + first_or_last = 1 # last + + l2 =(edgeOrderedList[0].centre - edLoop.centre).length + if l2 < bestSoFar: + bestIdxSoFar = edLoopIdx + bestSoFar = l2 + first_or_last = 0 # last + + if first_or_last: # add closest Last + edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) ) + else: # Add closest First + edgeOrderedList.insert(0, edgeLoops.pop(bestIdxSoFar) ) # First + + faces = [] + + for i in range(len(edgeOrderedList)-1): + faces.extend( skin2EdgeLoops(edgeOrderedList[i], edgeOrderedList[i+1], me, ob, 0) ) + if choice == 1 and len(edgeOrderedList) > 2: # Loop + faces.extend( skin2EdgeLoops(edgeOrderedList[0], edgeOrderedList[-1], me, ob, 0) ) + + # REMOVE SELECTED FACES. + MESH_MODE= ob.mode + if MESH_MODE == 'EDGE' or MESH_MODE == 'VERTEX': pass + elif MESH_MODE == 'FACE': + try: me.faces.delete(1, [ f for f in me.faces if f.sel ]) + except: pass + + if 1: # 2.5 + mesh_faces_extend(me, faces, ob.active_material_index) + me.update(calc_edges=True) + else: + me.faces.extend(faces, smooth = True) + + print('\nSkin done in %.4f sec.' % (time.time()-time1)) + + if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False) class MESH_OT_skin(bpy.types.Operator): - '''Bridge face loops.''' - - bl_idname = "mesh.skin" - bl_label = "Add Torus" - bl_register = True - bl_undo = True - - ''' - loft_method = EnumProperty(attr="loft_method", items=[(), ()], description="", default= True) - - ''' - - def execute(self, context): - main(context) - return ('FINISHED',) + '''Bridge face loops.''' + + bl_idname = "mesh.skin" + bl_label = "Add Torus" + bl_register = True + bl_undo = True + + ''' + loft_method = EnumProperty(attr="loft_method", items=[(), ()], description="", default= True) + + ''' + + def execute(self, context): + main(context) + return ('FINISHED',) # Register the operator @@ -653,4 +653,4 @@ import dynamic_menu menu_item = dynamic_menu.add(bpy.types.VIEW3D_MT_edit_mesh_faces, (lambda self, context: self.layout.operator("mesh.skin", text="Bridge Faces")) ) if __name__ == "__main__": - bpy.ops.mesh.skin() + bpy.ops.mesh.skin() diff --git a/release/scripts/op/object.py b/release/scripts/op/object.py index 4d3d8288833..50bbbf8158a 100644 --- a/release/scripts/op/object.py +++ b/release/scripts/op/object.py @@ -17,6 +17,42 @@ # ##### END GPL LICENSE BLOCK ##### import bpy +from bpy.props import * + + +class SelectPattern(bpy.types.Operator): + '''Select object matching a naming pattern.''' + bl_idname = "object.select_pattern" + bl_label = "Select Pattern" + bl_register = True + bl_undo = True + + pattern = StringProperty(name="Pattern", description="Name filter using '*' and '?' wildcard chars", maxlen=32, default="*") + case_sensitive = BoolProperty(name="Case Sensitive", description="Do a case sensitive compare", default=False) + extend = BoolProperty(name="Extend", description="Extend the existing selection", default=True) + + def execute(self, context): + + import fnmatch + + if self.properties.case_sensitive: + pattern_match = fnmatch.fnmatchcase + else: + pattern_match = lambda a, b: fnmatch.fnmatchcase(a.upper(), b.upper()) + + for ob in context.visible_objects: + if pattern_match(ob.name, self.properties.pattern): + ob.selected = True + elif not self.properties.extend: + ob.selected = False + + return ('FINISHED',) + + def invoke(self, context, event): + wm = context.manager + wm.invoke_props_popup(self, event) + return ('RUNNING_MODAL',) + class SubsurfSet(bpy.types.Operator): '''Sets a Subdivision Surface Level (1-5)''' @@ -25,8 +61,8 @@ class SubsurfSet(bpy.types.Operator): bl_label = "Subsurf Set" bl_register = True bl_undo = True - - level = bpy.props.IntProperty(name="Level", + + level = IntProperty(name="Level", default=1, min=0, max=6) def poll(self, context): @@ -41,12 +77,12 @@ class SubsurfSet(bpy.types.Operator): if mod.levels != level: mod.levels = level return ('FINISHED',) - + # adda new modifier mod = ob.modifiers.new("Subsurf", 'SUBSURF') mod.levels = level return ('FINISHED',) -# Register the operator +bpy.ops.add(SelectPattern) bpy.ops.add(SubsurfSet) diff --git a/release/scripts/op/presets.py b/release/scripts/op/presets.py index 0b2e959ff0c..84a60765fa4 100644 --- a/release/scripts/op/presets.py +++ b/release/scripts/op/presets.py @@ -4,12 +4,12 @@ # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@ -21,14 +21,14 @@ import os class AddPresetBase(bpy.types.Operator): '''Base preset class, only for subclassing - subclasses must define + subclasses must define - preset_values - preset_subdir ''' bl_idname = "render.preset_add" bl_label = "Add Render Preset" name = bpy.props.StringProperty(name="Name", description="Name of the preset, used to make the path name", maxlen= 64, default= "") - + def _as_filename(self, name): # could reuse for other presets for char in " !@#$%^&*(){}:\";'[]<>,./?": name = name.replace('.', '_') @@ -44,7 +44,7 @@ class AddPresetBase(bpy.types.Operator): target_path = bpy.utils.preset_paths(self.preset_subdir)[0] # we need some way to tell the user and system preset path file_preset = open(os.path.join(target_path, filename), 'w') - + for rna_path in self.preset_values: file_preset.write("%s = %s\n" % (rna_path, eval(rna_path))) @@ -100,13 +100,13 @@ class AddPresetSSS(AddPresetBase): ] preset_subdir = "sss" - + class AddPresetCloth(AddPresetBase): '''Add a Cloth Preset.''' bl_idname = "cloth.preset_add" bl_label = "Add Cloth Preset" name = AddPresetBase.name - + preset_values = [ "bpy.context.cloth.settings.quality", "bpy.context.cloth.settings.mass", @@ -115,7 +115,7 @@ class AddPresetCloth(AddPresetBase): "bpy.context.cloth.settings.spring_damping", "bpy.context.cloth.settings.air_damping", ] - + preset_subdir = "cloth" bpy.ops.add(AddPresetRender) diff --git a/release/scripts/op/uvcalc_smart_project.py b/release/scripts/op/uvcalc_smart_project.py index cc8aa5fe63a..2da7174ed99 100644 --- a/release/scripts/op/uvcalc_smart_project.py +++ b/release/scripts/op/uvcalc_smart_project.py @@ -1,24 +1,24 @@ -# -------------------------------------------------------------------------- -# Smart Projection UV Projection Unwrapper v1.2 by Campbell Barton (AKA Ideasman) -# -------------------------------------------------------------------------- -# ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# ***** END GPL LICENCE BLOCK ***** -# -------------------------------------------------------------------------- +# -------------------------------------------------------------------------- +# Smart Projection UV Projection Unwrapper v1.2 by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- #from Blender import Object, Draw, Window, sys, Mesh, Geometry @@ -40,96 +40,96 @@ USER_FILL_HOLES_QUALITY = None dict_matrix = {} def pointInTri2D(v, v1, v2, v3): - global dict_matrix - - key = v1.x, v1.y, v2.x, v2.y, v3.x, v3.y - - # Commented because its slower to do teh bounds check, we should realy cache the bounds info for each face. - ''' - # BOUNDS CHECK - xmin= 1000000 - ymin= 1000000 - - xmax= -1000000 - ymax= -1000000 - - for i in (0,2,4): - x= key[i] - y= key[i+1] - - if xmaxx: xmin= x - if ymin>y: ymin= y - - x= v.x - y= v.y - - if xxmax or y < ymin or y > ymax: - return False - # Done with bounds check - ''' - try: - mtx = dict_matrix[key] - if not mtx: - return False - except: - side1 = v2 - v1 - side2 = v3 - v1 - - nor = side1.cross(side2) - - l1 = [side1[0], side1[1], side1[2]] - l2 = [side2[0], side2[1], side2[2]] - l3 = [nor[0], nor[1], nor[2]] - - mtx = Matrix(l1, l2, l3) - - # Zero area 2d tri, even tho we throw away zerop area faces - # the projection UV can result in a zero area UV. - if not mtx.determinant(): - dict_matrix[key] = None - return False - - mtx.invert() - - dict_matrix[key] = mtx - - uvw = (v - v1) * mtx - return 0 <= uvw[0] and 0 <= uvw[1] and uvw[0] + uvw[1] <= 1 + global dict_matrix + + key = v1.x, v1.y, v2.x, v2.y, v3.x, v3.y + + # Commented because its slower to do teh bounds check, we should realy cache the bounds info for each face. + ''' + # BOUNDS CHECK + xmin= 1000000 + ymin= 1000000 + + xmax= -1000000 + ymax= -1000000 + + for i in (0,2,4): + x= key[i] + y= key[i+1] + + if xmaxx: xmin= x + if ymin>y: ymin= y + + x= v.x + y= v.y + + if xxmax or y < ymin or y > ymax: + return False + # Done with bounds check + ''' + try: + mtx = dict_matrix[key] + if not mtx: + return False + except: + side1 = v2 - v1 + side2 = v3 - v1 + + nor = side1.cross(side2) + + l1 = [side1[0], side1[1], side1[2]] + l2 = [side2[0], side2[1], side2[2]] + l3 = [nor[0], nor[1], nor[2]] + + mtx = Matrix(l1, l2, l3) + + # Zero area 2d tri, even tho we throw away zerop area faces + # the projection UV can result in a zero area UV. + if not mtx.determinant(): + dict_matrix[key] = None + return False + + mtx.invert() + + dict_matrix[key] = mtx + + uvw = (v - v1) * mtx + return 0 <= uvw[0] and 0 <= uvw[1] and uvw[0] + uvw[1] <= 1 + - def boundsIsland(faces): - minx = maxx = faces[0].uv[0][0] # Set initial bounds. - miny = maxy = faces[0].uv[0][1] - # print len(faces), minx, maxx, miny , maxy - for f in faces: - for uv in f.uv: - x= uv.x - y= uv.y - if xmaxx: maxx= x - if y>maxy: maxy= y - - return minx, miny, maxx, maxy + minx = maxx = faces[0].uv[0][0] # Set initial bounds. + miny = maxy = faces[0].uv[0][1] + # print len(faces), minx, maxx, miny , maxy + for f in faces: + for uv in f.uv: + x= uv.x + y= uv.y + if xmaxx: maxx= x + if y>maxy: maxy= y + + return minx, miny, maxx, maxy """ def boundsEdgeLoop(edges): - minx = maxx = edges[0][0] # Set initial bounds. - miny = maxy = edges[0][1] - # print len(faces), minx, maxx, miny , maxy - for ed in edges: - for pt in ed: - print 'ass' - x= pt[0] - y= pt[1] - if xmaxx: x= maxx - if y>maxy: y= maxy - - return minx, miny, maxx, maxy + minx = maxx = edges[0][0] # Set initial bounds. + miny = maxy = edges[0][1] + # print len(faces), minx, maxx, miny , maxy + for ed in edges: + for pt in ed: + print 'ass' + x= pt[0] + y= pt[1] + if xmaxx: x= maxx + if y>maxy: y= maxy + + return minx, miny, maxx, maxy """ # Turns the islands into a list of unpordered edges (Non internal) @@ -137,44 +137,44 @@ def boundsEdgeLoop(edges): # only returns outline edges for intersection tests. and unique points. def island2Edge(island): - - # Vert index edges - edges = {} - - unique_points= {} - - for f in island: - f_uvkey= map(tuple, f.uv) - - - for vIdx, edkey in enumerate(f.edge_keys): - unique_points[f_uvkey[vIdx]] = f.uv[vIdx] - - if f.v[vIdx].index > f.v[vIdx-1].index: - i1= vIdx-1; i2= vIdx - else: - i1= vIdx; i2= vIdx-1 - - try: edges[ f_uvkey[i1], f_uvkey[i2] ] *= 0 # sets eny edge with more then 1 user to 0 are not returned. - except: edges[ f_uvkey[i1], f_uvkey[i2] ] = (f.uv[i1] - f.uv[i2]).length, - - # If 2 are the same then they will be together, but full [a,b] order is not correct. - - # Sort by length - - - length_sorted_edges = [(Vector(key[0]), Vector(key[1]), value) for key, value in edges.items() if value != 0] - - try: length_sorted_edges.sort(key = lambda A: -A[2]) # largest first - except: length_sorted_edges.sort(lambda A, B: cmp(B[2], A[2])) - - # Its okay to leave the length in there. - #for e in length_sorted_edges: - # e.pop(2) - - # return edges and unique points - return length_sorted_edges, [v.__copy__().resize3D() for v in unique_points.values()] - + + # Vert index edges + edges = {} + + unique_points= {} + + for f in island: + f_uvkey= map(tuple, f.uv) + + + for vIdx, edkey in enumerate(f.edge_keys): + unique_points[f_uvkey[vIdx]] = f.uv[vIdx] + + if f.v[vIdx].index > f.v[vIdx-1].index: + i1= vIdx-1; i2= vIdx + else: + i1= vIdx; i2= vIdx-1 + + try: edges[ f_uvkey[i1], f_uvkey[i2] ] *= 0 # sets eny edge with more then 1 user to 0 are not returned. + except: edges[ f_uvkey[i1], f_uvkey[i2] ] = (f.uv[i1] - f.uv[i2]).length, + + # If 2 are the same then they will be together, but full [a,b] order is not correct. + + # Sort by length + + + length_sorted_edges = [(Vector(key[0]), Vector(key[1]), value) for key, value in edges.items() if value != 0] + + try: length_sorted_edges.sort(key = lambda A: -A[2]) # largest first + except: length_sorted_edges.sort(lambda A, B: cmp(B[2], A[2])) + + # Its okay to leave the length in there. + #for e in length_sorted_edges: + # e.pop(2) + + # return edges and unique points + return length_sorted_edges, [v.__copy__().resize3D() for v in unique_points.values()] + # ========================= NOT WORKING???? # Find if a points inside an edge loop, un-orderd. # pt is and x/y @@ -182,97 +182,97 @@ def island2Edge(island): # #offsets are the edge x and y offset. """ def pointInEdges(pt, edges): - # - x1 = pt[0] - y1 = pt[1] - - # Point to the left of this line. - x2 = -100000 - y2 = -10000 - intersectCount = 0 - for ed in edges: - xi, yi = lineIntersection2D(x1,y1, x2,y2, ed[0][0], ed[0][1], ed[1][0], ed[1][1]) - if xi != None: # Is there an intersection. - intersectCount+=1 - - return intersectCount % 2 + # + x1 = pt[0] + y1 = pt[1] + + # Point to the left of this line. + x2 = -100000 + y2 = -10000 + intersectCount = 0 + for ed in edges: + xi, yi = lineIntersection2D(x1,y1, x2,y2, ed[0][0], ed[0][1], ed[1][0], ed[1][1]) + if xi != None: # Is there an intersection. + intersectCount+=1 + + return intersectCount % 2 """ def pointInIsland(pt, island): - vec1 = Vector(); vec2 = Vector(); vec3 = Vector() - for f in island: - vec1.x, vec1.y = f.uv[0] - vec2.x, vec2.y = f.uv[1] - vec3.x, vec3.y = f.uv[2] + vec1 = Vector(); vec2 = Vector(); vec3 = Vector() + for f in island: + vec1.x, vec1.y = f.uv[0] + vec2.x, vec2.y = f.uv[1] + vec3.x, vec3.y = f.uv[2] - if pointInTri2D(pt, vec1, vec2, vec3): - return True - - if len(f.v) == 4: - vec1.x, vec1.y = f.uv[0] - vec2.x, vec2.y = f.uv[2] - vec3.x, vec3.y = f.uv[3] - if pointInTri2D(pt, vec1, vec2, vec3): - return True - return False + if pointInTri2D(pt, vec1, vec2, vec3): + return True + + if len(f.v) == 4: + vec1.x, vec1.y = f.uv[0] + vec2.x, vec2.y = f.uv[2] + vec3.x, vec3.y = f.uv[3] + if pointInTri2D(pt, vec1, vec2, vec3): + return True + return False # box is (left,bottom, right, top) def islandIntersectUvIsland(source, target, SourceOffset): - # Is 1 point in the box, inside the vertLoops - edgeLoopsSource = source[6] # Pretend this is offset - edgeLoopsTarget = target[6] - - # Edge intersect test - for ed in edgeLoopsSource: - for seg in edgeLoopsTarget: - i = Geometry.LineIntersect2D(\ - seg[0], seg[1], SourceOffset+ed[0], SourceOffset+ed[1]) - if i: - return 1 # LINE INTERSECTION - - # 1 test for source being totally inside target - SourceOffset.resize3D() - for pv in source[7]: - if pointInIsland(pv+SourceOffset, target[0]): - return 2 # SOURCE INSIDE TARGET - - # 2 test for a part of the target being totaly inside the source. - for pv in target[7]: - if pointInIsland(pv-SourceOffset, source[0]): - return 3 # PART OF TARGET INSIDE SOURCE. + # Is 1 point in the box, inside the vertLoops + edgeLoopsSource = source[6] # Pretend this is offset + edgeLoopsTarget = target[6] - return 0 # NO INTERSECTION + # Edge intersect test + for ed in edgeLoopsSource: + for seg in edgeLoopsTarget: + i = Geometry.LineIntersect2D(\ + seg[0], seg[1], SourceOffset+ed[0], SourceOffset+ed[1]) + if i: + return 1 # LINE INTERSECTION + + # 1 test for source being totally inside target + SourceOffset.resize3D() + for pv in source[7]: + if pointInIsland(pv+SourceOffset, target[0]): + return 2 # SOURCE INSIDE TARGET + + # 2 test for a part of the target being totaly inside the source. + for pv in target[7]: + if pointInIsland(pv-SourceOffset, source[0]): + return 3 # PART OF TARGET INSIDE SOURCE. + + return 0 # NO INTERSECTION # Returns the X/y Bounds of a list of vectors. def testNewVecLs2DRotIsBetter(vecs, mat=-1, bestAreaSoFar = -1): - - # UV's will never extend this far. - minx = miny = BIG_NUM - maxx = maxy = -BIG_NUM - - for i, v in enumerate(vecs): - - # Do this allong the way - if mat != -1: - v = vecs[i] = v*mat - x= v.x - y= v.y - if xmaxx: maxx= x - if y>maxy: maxy= y - - # Spesific to this algo, bail out if we get bigger then the current area - if bestAreaSoFar != -1 and (maxx-minx) * (maxy-miny) > bestAreaSoFar: - return (BIG_NUM, None), None - w = maxx-minx - h = maxy-miny - return (w*h, w,h), vecs # Area, vecs - + + # UV's will never extend this far. + minx = miny = BIG_NUM + maxx = maxy = -BIG_NUM + + for i, v in enumerate(vecs): + + # Do this allong the way + if mat != -1: + v = vecs[i] = v*mat + x= v.x + y= v.y + if xmaxx: maxx= x + if y>maxy: maxy= y + + # Spesific to this algo, bail out if we get bigger then the current area + if bestAreaSoFar != -1 and (maxx-minx) * (maxy-miny) > bestAreaSoFar: + return (BIG_NUM, None), None + w = maxx-minx + h = maxy-miny + return (w*h, w,h), vecs # Area, vecs + # Takes a list of faces that make up a UV island and rotate # until they optimally fit inside a square. ROTMAT_2D_POS_90D = RotationMatrix( radians(90.0), 2) @@ -281,855 +281,855 @@ ROTMAT_2D_POS_45D = RotationMatrix( radians(45.0), 2) RotMatStepRotation = [] rot_angle = 22.5 #45.0/2 while rot_angle > 0.1: - RotMatStepRotation.append([\ - RotationMatrix( radians(rot_angle), 2),\ - RotationMatrix( radians(-rot_angle), 2)]) - - rot_angle = rot_angle/2.0 - + RotMatStepRotation.append([\ + RotationMatrix( radians(rot_angle), 2),\ + RotationMatrix( radians(-rot_angle), 2)]) + + rot_angle = rot_angle/2.0 + def optiRotateUvIsland(faces): - global currentArea - - # Bestfit Rotation - def best2dRotation(uvVecs, MAT1, MAT2): - global currentArea - - newAreaPos, newfaceProjectionGroupListPos =\ - testNewVecLs2DRotIsBetter(uvVecs[:], MAT1, currentArea[0]) - - - # Why do I use newpos here? May as well give the best area to date for an early bailout - # some slight speed increase in this. - # If the new rotation is smaller then the existing, we can - # avoid copying a list and overwrite the old, crappy one. - - if newAreaPos[0] < currentArea[0]: - newAreaNeg, newfaceProjectionGroupListNeg =\ - testNewVecLs2DRotIsBetter(uvVecs, MAT2, newAreaPos[0]) # Reuse the old bigger list. - else: - newAreaNeg, newfaceProjectionGroupListNeg =\ - testNewVecLs2DRotIsBetter(uvVecs[:], MAT2, currentArea[0]) # Cant reuse, make a copy. - - - # Now from the 3 options we need to discover which to use - # we have cerrentArea/newAreaPos/newAreaNeg - bestArea = min(currentArea[0], newAreaPos[0], newAreaNeg[0]) - - if currentArea[0] == bestArea: - return uvVecs - elif newAreaPos[0] == bestArea: - uvVecs = newfaceProjectionGroupListPos - currentArea = newAreaPos - elif newAreaNeg[0] == bestArea: - uvVecs = newfaceProjectionGroupListNeg - currentArea = newAreaNeg - - return uvVecs - - - # Serialized UV coords to Vectors - uvVecs = [uv for f in faces for uv in f.uv] - - # Theres a small enough number of these to hard code it - # rather then a loop. - - # Will not modify anything - currentArea, dummy =\ - testNewVecLs2DRotIsBetter(uvVecs) - - - # Try a 45d rotation - newAreaPos, newfaceProjectionGroupListPos = testNewVecLs2DRotIsBetter(uvVecs[:], ROTMAT_2D_POS_45D, currentArea[0]) - - if newAreaPos[0] < currentArea[0]: - uvVecs = newfaceProjectionGroupListPos - currentArea = newAreaPos - # 45d done - - # Testcase different rotations and find the onfe that best fits in a square - for ROTMAT in RotMatStepRotation: - uvVecs = best2dRotation(uvVecs, ROTMAT[0], ROTMAT[1]) - - # Only if you want it, make faces verticle! - if currentArea[1] > currentArea[2]: - # Rotate 90d - # Work directly on the list, no need to return a value. - testNewVecLs2DRotIsBetter(uvVecs, ROTMAT_2D_POS_90D) - - - # Now write the vectors back to the face UV's - i = 0 # count the serialized uv/vectors - for f in faces: - #f.uv = [uv for uv in uvVecs[i:len(f)+i] ] - for j, k in enumerate(range(i, len(f.v)+i)): - f.uv[j][:] = uvVecs[k] - i += len(f.v) + global currentArea + + # Bestfit Rotation + def best2dRotation(uvVecs, MAT1, MAT2): + global currentArea + + newAreaPos, newfaceProjectionGroupListPos =\ + testNewVecLs2DRotIsBetter(uvVecs[:], MAT1, currentArea[0]) + + + # Why do I use newpos here? May as well give the best area to date for an early bailout + # some slight speed increase in this. + # If the new rotation is smaller then the existing, we can + # avoid copying a list and overwrite the old, crappy one. + + if newAreaPos[0] < currentArea[0]: + newAreaNeg, newfaceProjectionGroupListNeg =\ + testNewVecLs2DRotIsBetter(uvVecs, MAT2, newAreaPos[0]) # Reuse the old bigger list. + else: + newAreaNeg, newfaceProjectionGroupListNeg =\ + testNewVecLs2DRotIsBetter(uvVecs[:], MAT2, currentArea[0]) # Cant reuse, make a copy. + + + # Now from the 3 options we need to discover which to use + # we have cerrentArea/newAreaPos/newAreaNeg + bestArea = min(currentArea[0], newAreaPos[0], newAreaNeg[0]) + + if currentArea[0] == bestArea: + return uvVecs + elif newAreaPos[0] == bestArea: + uvVecs = newfaceProjectionGroupListPos + currentArea = newAreaPos + elif newAreaNeg[0] == bestArea: + uvVecs = newfaceProjectionGroupListNeg + currentArea = newAreaNeg + + return uvVecs + + + # Serialized UV coords to Vectors + uvVecs = [uv for f in faces for uv in f.uv] + + # Theres a small enough number of these to hard code it + # rather then a loop. + + # Will not modify anything + currentArea, dummy =\ + testNewVecLs2DRotIsBetter(uvVecs) + + + # Try a 45d rotation + newAreaPos, newfaceProjectionGroupListPos = testNewVecLs2DRotIsBetter(uvVecs[:], ROTMAT_2D_POS_45D, currentArea[0]) + + if newAreaPos[0] < currentArea[0]: + uvVecs = newfaceProjectionGroupListPos + currentArea = newAreaPos + # 45d done + + # Testcase different rotations and find the onfe that best fits in a square + for ROTMAT in RotMatStepRotation: + uvVecs = best2dRotation(uvVecs, ROTMAT[0], ROTMAT[1]) + + # Only if you want it, make faces verticle! + if currentArea[1] > currentArea[2]: + # Rotate 90d + # Work directly on the list, no need to return a value. + testNewVecLs2DRotIsBetter(uvVecs, ROTMAT_2D_POS_90D) + + + # Now write the vectors back to the face UV's + i = 0 # count the serialized uv/vectors + for f in faces: + #f.uv = [uv for uv in uvVecs[i:len(f)+i] ] + for j, k in enumerate(range(i, len(f.v)+i)): + f.uv[j][:] = uvVecs[k] + i += len(f.v) # Takes an island list and tries to find concave, hollow areas to pack smaller islands into. def mergeUvIslands(islandList): - global USER_FILL_HOLES - global USER_FILL_HOLES_QUALITY - - - # Pack islands to bottom LHS - # Sync with island - - #islandTotFaceArea = [] # A list of floats, each island area - #islandArea = [] # a list of tuples ( area, w,h) - - - decoratedIslandList = [] - - islandIdx = len(islandList) - while islandIdx: - islandIdx-=1 - minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx]) - w, h = maxx-minx, maxy-miny - - totFaceArea = 0 - offset= Vector(minx, miny) - for f in islandList[islandIdx]: - for uv in f.uv: - uv -= offset - - totFaceArea += f.area - - islandBoundsArea = w*h - efficiency = abs(islandBoundsArea - totFaceArea) - - # UV Edge list used for intersections as well as unique points. - edges, uniqueEdgePoints = island2Edge(islandList[islandIdx]) - - decoratedIslandList.append([islandList[islandIdx], totFaceArea, efficiency, islandBoundsArea, w,h, edges, uniqueEdgePoints]) - - - # Sort by island bounding box area, smallest face area first. - # no.. chance that to most simple edge loop first. - decoratedIslandListAreaSort =decoratedIslandList[:] - - decoratedIslandListAreaSort.sort(key = lambda A: A[3]) - - # sort by efficiency, Least Efficient first. - decoratedIslandListEfficSort = decoratedIslandList[:] - # decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2])) + global USER_FILL_HOLES + global USER_FILL_HOLES_QUALITY - decoratedIslandListEfficSort.sort(key = lambda A: -A[2]) - # ================================================== THESE CAN BE TWEAKED. - # This is a quality value for the number of tests. - # from 1 to 4, generic quality value is from 1 to 100 - USER_STEP_QUALITY = ((USER_FILL_HOLES_QUALITY - 1) / 25.0) + 1 - - # If 100 will test as long as there is enough free space. - # this is rarely enough, and testing takes a while, so lower quality speeds this up. - - # 1 means they have the same quality - USER_FREE_SPACE_TO_TEST_QUALITY = 1 + (((100 - USER_FILL_HOLES_QUALITY)/100.0) *5) - - #print 'USER_STEP_QUALITY', USER_STEP_QUALITY - #print 'USER_FREE_SPACE_TO_TEST_QUALITY', USER_FREE_SPACE_TO_TEST_QUALITY - - removedCount = 0 - - areaIslandIdx = 0 - ctrl = Window.Qual.CTRL - BREAK= False - while areaIslandIdx < len(decoratedIslandListAreaSort) and not BREAK: - sourceIsland = decoratedIslandListAreaSort[areaIslandIdx] - # Alredy packed? - if not sourceIsland[0]: - areaIslandIdx+=1 - else: - efficIslandIdx = 0 - while efficIslandIdx < len(decoratedIslandListEfficSort) and not BREAK: - - if Window.GetKeyQualifiers() & ctrl: - BREAK= True - break - - # Now we have 2 islands, is the efficience of the islands lowers theres an - # increasing likely hood that we can fit merge into the bigger UV island. - # this ensures a tight fit. - - # Just use figures we have about user/unused area to see if they might fit. - - targetIsland = decoratedIslandListEfficSort[efficIslandIdx] - - - if sourceIsland[0] == targetIsland[0] or\ - not targetIsland[0] or\ - not sourceIsland[0]: - pass - else: - - # ([island, totFaceArea, efficiency, islandArea, w,h]) - # Waisted space on target is greater then UV bounding island area. - - - # if targetIsland[3] > (sourceIsland[2]) and\ # - # print USER_FREE_SPACE_TO_TEST_QUALITY, 'ass' - if targetIsland[2] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\ - targetIsland[4] > sourceIsland[4] and\ - targetIsland[5] > sourceIsland[5]: - - # DEBUG # print '%.10f %.10f' % (targetIsland[3], sourceIsland[1]) - - # These enough spare space lets move the box until it fits - - # How many times does the source fit into the target x/y - blockTestXUnit = targetIsland[4]/sourceIsland[4] - blockTestYUnit = targetIsland[5]/sourceIsland[5] - - boxLeft = 0 - - - # Distllllance we can move between whilst staying inside the targets bounds. - testWidth = targetIsland[4] - sourceIsland[4] - testHeight = targetIsland[5] - sourceIsland[5] - - # Increment we move each test. x/y - xIncrement = (testWidth / (blockTestXUnit * ((USER_STEP_QUALITY/50)+0.1))) - yIncrement = (testHeight / (blockTestYUnit * ((USER_STEP_QUALITY/50)+0.1))) + # Pack islands to bottom LHS + # Sync with island - # Make sure were not moving less then a 3rg of our width/height - if xIncrement (sourceIsland[2]) and\ # + # print USER_FREE_SPACE_TO_TEST_QUALITY, 'ass' + if targetIsland[2] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\ + targetIsland[4] > sourceIsland[4] and\ + targetIsland[5] > sourceIsland[5]: + + # DEBUG # print '%.10f %.10f' % (targetIsland[3], sourceIsland[1]) + + # These enough spare space lets move the box until it fits + + # How many times does the source fit into the target x/y + blockTestXUnit = targetIsland[4]/sourceIsland[4] + blockTestYUnit = targetIsland[5]/sourceIsland[5] + + boxLeft = 0 + + + # Distllllance we can move between whilst staying inside the targets bounds. + testWidth = targetIsland[4] - sourceIsland[4] + testHeight = targetIsland[5] - sourceIsland[5] + + # Increment we move each test. x/y + xIncrement = (testWidth / (blockTestXUnit * ((USER_STEP_QUALITY/50)+0.1))) + yIncrement = (testHeight / (blockTestYUnit * ((USER_STEP_QUALITY/50)+0.1))) + + # Make sure were not moving less then a 3rg of our width/height + if xIncrement testWidth: - boxBottom += yIncrement - boxLeft = 0.0 - else: - boxLeft += xIncrement - ##print testcount - - efficIslandIdx+=1 - areaIslandIdx+=1 - - # Remove empty islands - i = len(islandList) - while i: - i-=1 - if not islandList[i]: - del islandList[i] # Can increment islands removed here. + # Move faces into new island and offset + targetIsland[0].extend(sourceIsland[0]) + offset= Vector(boxLeft, boxBottom) + + for f in sourceIsland[0]: + for uv in f.uv: + uv+= offset + + sourceIsland[0][:] = [] # Empty + + + # Move edge loop into new and offset. + # targetIsland[6].extend(sourceIsland[6]) + #while sourceIsland[6]: + targetIsland[6].extend( [ (\ + (e[0]+offset, e[1]+offset, e[2])\ + ) for e in sourceIsland[6] ] ) + + sourceIsland[6][:] = [] # Empty + + # Sort by edge length, reverse so biggest are first. + + try: targetIsland[6].sort(key = lambda A: A[2]) + except: targetIsland[6].sort(lambda B,A: cmp(A[2], B[2] )) + + + targetIsland[7].extend(sourceIsland[7]) + offset= Vector(boxLeft, boxBottom, 0) + for p in sourceIsland[7]: + p+= offset + + sourceIsland[7][:] = [] + + + # Decrement the efficiency + targetIsland[1]+=sourceIsland[1] # Increment totFaceArea + targetIsland[2]-=sourceIsland[1] # Decrement efficiency + # IF we ever used these again, should set to 0, eg + sourceIsland[2] = 0 # No area if anyone wants to know + + break + + + # INCREMENR NEXT LOCATION + if boxLeft > testWidth: + boxBottom += yIncrement + boxLeft = 0.0 + else: + boxLeft += xIncrement + ##print testcount + + efficIslandIdx+=1 + areaIslandIdx+=1 + + # Remove empty islands + i = len(islandList) + while i: + i-=1 + if not islandList[i]: + del islandList[i] # Can increment islands removed here. # Takes groups of faces. assumes face groups are UV groups. def getUvIslands(faceGroups, me): - - # Get seams so we dont cross over seams - edge_seams = {} # shoudl be a set - for ed in me.edges: - if ed.seam: - edge_seams[ed.key] = None # dummy var- use sets! - # Done finding seams - - - islandList = [] - + + # Get seams so we dont cross over seams + edge_seams = {} # shoudl be a set + for ed in me.edges: + if ed.seam: + edge_seams[ed.key] = None # dummy var- use sets! + # Done finding seams + + + islandList = [] + #XXX Window.DrawProgressBar(0.0, 'Splitting %d projection groups into UV islands:' % len(faceGroups)) - #print '\tSplitting %d projection groups into UV islands:' % len(faceGroups), - # Find grouped faces - - faceGroupIdx = len(faceGroups) - - while faceGroupIdx: - faceGroupIdx-=1 - faces = faceGroups[faceGroupIdx] - - if not faces: - continue - - # Build edge dict - edge_users = {} - - for i, f in enumerate(faces): - for ed_key in f.edge_keys: - if ed_key in edge_seams: # DELIMIT SEAMS! ;) - edge_users[ed_key] = [] # so as not to raise an error - else: - try: edge_users[ed_key].append(i) - except: edge_users[ed_key] = [i] - - # Modes - # 0 - face not yet touched. - # 1 - added to island list, and need to search - # 2 - touched and searched - dont touch again. - face_modes = [0] * len(faces) # initialize zero - untested. - - face_modes[0] = 1 # start the search with face 1 - - newIsland = [] - - newIsland.append(faces[0]) - - - ok = True - while ok: - - ok = True - while ok: - ok= False - for i in range(len(faces)): - if face_modes[i] == 1: # search - for ed_key in faces[i].edge_keys: - for ii in edge_users[ed_key]: - if i != ii and face_modes[ii] == 0: - face_modes[ii] = ok = 1 # mark as searched - newIsland.append(faces[ii]) - - # mark as searched, dont look again. - face_modes[i] = 2 - - islandList.append(newIsland) - - ok = False - for i in range(len(faces)): - if face_modes[i] == 0: - newIsland = [] - newIsland.append(faces[i]) - - face_modes[i] = ok = 1 - break - # if not ok will stop looping - + #print '\tSplitting %d projection groups into UV islands:' % len(faceGroups), + # Find grouped faces + + faceGroupIdx = len(faceGroups) + + while faceGroupIdx: + faceGroupIdx-=1 + faces = faceGroups[faceGroupIdx] + + if not faces: + continue + + # Build edge dict + edge_users = {} + + for i, f in enumerate(faces): + for ed_key in f.edge_keys: + if ed_key in edge_seams: # DELIMIT SEAMS! ;) + edge_users[ed_key] = [] # so as not to raise an error + else: + try: edge_users[ed_key].append(i) + except: edge_users[ed_key] = [i] + + # Modes + # 0 - face not yet touched. + # 1 - added to island list, and need to search + # 2 - touched and searched - dont touch again. + face_modes = [0] * len(faces) # initialize zero - untested. + + face_modes[0] = 1 # start the search with face 1 + + newIsland = [] + + newIsland.append(faces[0]) + + + ok = True + while ok: + + ok = True + while ok: + ok= False + for i in range(len(faces)): + if face_modes[i] == 1: # search + for ed_key in faces[i].edge_keys: + for ii in edge_users[ed_key]: + if i != ii and face_modes[ii] == 0: + face_modes[ii] = ok = 1 # mark as searched + newIsland.append(faces[ii]) + + # mark as searched, dont look again. + face_modes[i] = 2 + + islandList.append(newIsland) + + ok = False + for i in range(len(faces)): + if face_modes[i] == 0: + newIsland = [] + newIsland.append(faces[i]) + + face_modes[i] = ok = 1 + break + # if not ok will stop looping + #XXX Window.DrawProgressBar(0.1, 'Optimizing Rotation for %i UV Islands' % len(islandList)) - - for island in islandList: - optiRotateUvIsland(island) - - return islandList - + + for island in islandList: + optiRotateUvIsland(island) + + return islandList + def packIslands(islandList): - if USER_FILL_HOLES: + if USER_FILL_HOLES: #XXX Window.DrawProgressBar(0.1, 'Merging Islands (Ctrl: skip merge)...') - mergeUvIslands(islandList) # Modify in place - - - # Now we have UV islands, we need to pack them. - - # Make a synchronised list with the islands - # so we can box pak the islands. - packBoxes = [] - - # Keep a list of X/Y offset so we can save time by writing the - # uv's and packed data in one pass. - islandOffsetList = [] - - islandIdx = 0 - - while islandIdx < len(islandList): - minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx]) - - w, h = maxx-minx, maxy-miny - - if USER_ISLAND_MARGIN: - minx -= USER_ISLAND_MARGIN# *w - miny -= USER_ISLAND_MARGIN# *h - maxx += USER_ISLAND_MARGIN# *w - maxy += USER_ISLAND_MARGIN# *h - - # recalc width and height - w, h = maxx-minx, maxy-miny - - if w < 0.00001 or h < 0.00001: - del islandList[islandIdx] - islandIdx -=1 - continue - - '''Save the offset to be applied later, - we could apply to the UVs now and allign them to the bottom left hand area - of the UV coords like the box packer imagines they are - but, its quicker just to remember their offset and - apply the packing and offset in 1 pass ''' - islandOffsetList.append((minx, miny)) - - # Add to boxList. use the island idx for the BOX id. - packBoxes.append([0, 0, w, h]) - islandIdx+=1 - - # Now we have a list of boxes to pack that syncs - # with the islands. - - #print '\tPacking UV Islands...' + mergeUvIslands(islandList) # Modify in place + + + # Now we have UV islands, we need to pack them. + + # Make a synchronised list with the islands + # so we can box pak the islands. + packBoxes = [] + + # Keep a list of X/Y offset so we can save time by writing the + # uv's and packed data in one pass. + islandOffsetList = [] + + islandIdx = 0 + + while islandIdx < len(islandList): + minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx]) + + w, h = maxx-minx, maxy-miny + + if USER_ISLAND_MARGIN: + minx -= USER_ISLAND_MARGIN# *w + miny -= USER_ISLAND_MARGIN# *h + maxx += USER_ISLAND_MARGIN# *w + maxy += USER_ISLAND_MARGIN# *h + + # recalc width and height + w, h = maxx-minx, maxy-miny + + if w < 0.00001 or h < 0.00001: + del islandList[islandIdx] + islandIdx -=1 + continue + + '''Save the offset to be applied later, + we could apply to the UVs now and allign them to the bottom left hand area + of the UV coords like the box packer imagines they are + but, its quicker just to remember their offset and + apply the packing and offset in 1 pass ''' + islandOffsetList.append((minx, miny)) + + # Add to boxList. use the island idx for the BOX id. + packBoxes.append([0, 0, w, h]) + islandIdx+=1 + + # Now we have a list of boxes to pack that syncs + # with the islands. + + #print '\tPacking UV Islands...' #XXX Window.DrawProgressBar(0.7, 'Packing %i UV Islands...' % len(packBoxes) ) - - time1 = time.time() - packWidth, packHeight = Geometry.BoxPack2D(packBoxes) - - # print 'Box Packing Time:', time.time() - time1 - - #if len(pa ckedLs) != len(islandList): - # raise "Error packed boxes differes from original length" - - #print '\tWriting Packed Data to faces' + + time1 = time.time() + packWidth, packHeight = Geometry.BoxPack2D(packBoxes) + + # print 'Box Packing Time:', time.time() - time1 + + #if len(pa ckedLs) != len(islandList): + # raise "Error packed boxes differes from original length" + + #print '\tWriting Packed Data to faces' #XXX Window.DrawProgressBar(0.8, 'Writing Packed Data to faces') - - # Sort by ID, so there in sync again - islandIdx = len(islandList) - # Having these here avoids devide by 0 - if islandIdx: - - if USER_STRETCH_ASPECT: - # Maximize to uv area?? Will write a normalize function. - xfactor = 1.0 / packWidth - yfactor = 1.0 / packHeight - else: - # Keep proportions. - xfactor = yfactor = 1.0 / max(packWidth, packHeight) - - while islandIdx: - islandIdx -=1 - # Write the packed values to the UV's - - xoffset = packBoxes[islandIdx][0] - islandOffsetList[islandIdx][0] - yoffset = packBoxes[islandIdx][1] - islandOffsetList[islandIdx][1] - - for f in islandList[islandIdx]: # Offsetting the UV's so they fit in there packed box - for uv in f.uv: - uv.x= (uv.x+xoffset) * xfactor - uv.y= (uv.y+yoffset) * yfactor - - + + # Sort by ID, so there in sync again + islandIdx = len(islandList) + # Having these here avoids devide by 0 + if islandIdx: + + if USER_STRETCH_ASPECT: + # Maximize to uv area?? Will write a normalize function. + xfactor = 1.0 / packWidth + yfactor = 1.0 / packHeight + else: + # Keep proportions. + xfactor = yfactor = 1.0 / max(packWidth, packHeight) + + while islandIdx: + islandIdx -=1 + # Write the packed values to the UV's + + xoffset = packBoxes[islandIdx][0] - islandOffsetList[islandIdx][0] + yoffset = packBoxes[islandIdx][1] - islandOffsetList[islandIdx][1] + + for f in islandList[islandIdx]: # Offsetting the UV's so they fit in there packed box + for uv in f.uv: + uv.x= (uv.x+xoffset) * xfactor + uv.y= (uv.y+yoffset) * yfactor + + def VectoMat(vec): - a3 = vec.__copy__().normalize() - - up = Vector(0,0,1) - if abs(a3.dot(up)) == 1.0: - up = Vector(0,1,0) - - a1 = a3.cross(up).normalize() - a2 = a3.cross(a1) - return Matrix([a1[0], a1[1], a1[2]], [a2[0], a2[1], a2[2]], [a3[0], a3[1], a3[2]]) + a3 = vec.__copy__().normalize() + + up = Vector(0,0,1) + if abs(a3.dot(up)) == 1.0: + up = Vector(0,1,0) + + a1 = a3.cross(up).normalize() + a2 = a3.cross(a1) + return Matrix([a1[0], a1[1], a1[2]], [a2[0], a2[1], a2[2]], [a3[0], a3[1], a3[2]]) class thickface(object): - __slost__= 'v', 'uv', 'no', 'area', 'edge_keys' - def __init__(self, face, uvface, mesh_verts): - self.v = [mesh_verts[i] for i in face.verts] - if len(self.v)==4: - self.uv = uvface.uv1, uvface.uv2, uvface.uv3, uvface.uv4 - else: - self.uv = uvface.uv1, uvface.uv2, uvface.uv3 - - self.no = face.normal - self.area = face.area - self.edge_keys = face.edge_keys + __slost__= 'v', 'uv', 'no', 'area', 'edge_keys' + def __init__(self, face, uvface, mesh_verts): + self.v = [mesh_verts[i] for i in face.verts] + if len(self.v)==4: + self.uv = uvface.uv1, uvface.uv2, uvface.uv3, uvface.uv4 + else: + self.uv = uvface.uv1, uvface.uv2, uvface.uv3 + + self.no = face.normal + self.area = face.area + self.edge_keys = face.edge_keys global ob ob = None def main(context, island_margin, projection_limit): - global USER_FILL_HOLES - global USER_FILL_HOLES_QUALITY - global USER_STRETCH_ASPECT - global USER_ISLAND_MARGIN - -#XXX objects= bpy.data.scenes.active.objects - objects = context.selected_editable_objects - - - # we can will tag them later. - obList = [ob for ob in objects if ob.type == 'MESH'] - - # Face select object may not be selected. -#XXX ob = objects.active - ob= objects[0] + global USER_FILL_HOLES + global USER_FILL_HOLES_QUALITY + global USER_STRETCH_ASPECT + global USER_ISLAND_MARGIN + +#XXX objects= bpy.data.scenes.active.objects + objects = context.selected_editable_objects + + + # we can will tag them later. + obList = [ob for ob in objects if ob.type == 'MESH'] + + # Face select object may not be selected. +#XXX ob = objects.active + ob= objects[0] + + if ob and ob.selected == 0 and ob.type == 'MESH': + # Add to the list + obList =[ob] + del objects + + if not obList: + raise('error, no selected mesh objects') + + # Create the variables. + USER_PROJECTION_LIMIT = projection_limit + USER_ONLY_SELECTED_FACES = (1) + USER_SHARE_SPACE = (1) # Only for hole filling. + USER_STRETCH_ASPECT = (1) # Only for hole filling. + USER_ISLAND_MARGIN = island_margin # Only for hole filling. + USER_FILL_HOLES = (0) + USER_FILL_HOLES_QUALITY = (50) # Only for hole filling. + USER_VIEW_INIT = (0) # Only for hole filling. + USER_AREA_WEIGHT = (1) # Only for hole filling. + + # Reuse variable + if len(obList) == 1: + ob = "Unwrap %i Selected Mesh" + else: + ob = "Unwrap %i Selected Meshes" + + # HACK, loop until mouse is lifted. + ''' + while Window.GetMouseButtons() != 0: + time.sleep(10) + ''' - if ob and ob.selected == 0 and ob.type == 'MESH': - # Add to the list - obList =[ob] - del objects - - if not obList: - raise('error, no selected mesh objects') - - # Create the variables. - USER_PROJECTION_LIMIT = projection_limit - USER_ONLY_SELECTED_FACES = (1) - USER_SHARE_SPACE = (1) # Only for hole filling. - USER_STRETCH_ASPECT = (1) # Only for hole filling. - USER_ISLAND_MARGIN = island_margin # Only for hole filling. - USER_FILL_HOLES = (0) - USER_FILL_HOLES_QUALITY = (50) # Only for hole filling. - USER_VIEW_INIT = (0) # Only for hole filling. - USER_AREA_WEIGHT = (1) # Only for hole filling. - - # Reuse variable - if len(obList) == 1: - ob = "Unwrap %i Selected Mesh" - else: - ob = "Unwrap %i Selected Meshes" - - # HACK, loop until mouse is lifted. - ''' - while Window.GetMouseButtons() != 0: - time.sleep(10) - ''' - #XXX if not Draw.PupBlock(ob % len(obList), pup_block): #XXX return #XXX del ob - - # Convert from being button types - - USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD) - USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT/2) * DEG_TO_RAD) - - - # Toggle Edit mode - is_editmode = (context.active_object.mode == 'EDIT') - if is_editmode: - bpy.ops.object.mode_set(mode='OBJECT') - # Assume face select mode! an annoying hack to toggle face select mode because Mesh dosent like faceSelectMode. - - if USER_SHARE_SPACE: - # Sort by data name so we get consistant results - obList.sort(key = lambda ob: ob.data.name) - collected_islandList= [] - -#XXX Window.WaitCursor(1) - - time1 = time.time() - - # Tag as False se we dont operate on teh same mesh twice. -#XXX bpy.data.meshes.tag = False - for me in bpy.data.meshes: - me.tag = False - - for ob in obList: - me = ob.data - - if me.tag or me.library: - continue - - # Tag as used - me.tag = True - - if len(me.uv_textures)==0: # Mesh has no UV Coords, dont bother. - me.add_uv_texture() - - uv_layer = me.active_uv_texture.data - me_verts = list(me.verts) - - if USER_ONLY_SELECTED_FACES: - meshFaces = [thickface(f, uv_layer[i], me_verts) for i, f in enumerate(me.faces) if f.selected] - #else: - # meshFaces = map(thickface, me.faces) - - if not meshFaces: - continue - + # Convert from being button types + + USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD) + USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT/2) * DEG_TO_RAD) + + + # Toggle Edit mode + is_editmode = (context.active_object.mode == 'EDIT') + if is_editmode: + bpy.ops.object.mode_set(mode='OBJECT') + # Assume face select mode! an annoying hack to toggle face select mode because Mesh dosent like faceSelectMode. + + if USER_SHARE_SPACE: + # Sort by data name so we get consistant results + obList.sort(key = lambda ob: ob.data.name) + collected_islandList= [] + +#XXX Window.WaitCursor(1) + + time1 = time.time() + + # Tag as False se we dont operate on teh same mesh twice. +#XXX bpy.data.meshes.tag = False + for me in bpy.data.meshes: + me.tag = False + + + for ob in obList: + me = ob.data + + if me.tag or me.library: + continue + + # Tag as used + me.tag = True + + if len(me.uv_textures)==0: # Mesh has no UV Coords, dont bother. + me.add_uv_texture() + + uv_layer = me.active_uv_texture.data + me_verts = list(me.verts) + + if USER_ONLY_SELECTED_FACES: + meshFaces = [thickface(f, uv_layer[i], me_verts) for i, f in enumerate(me.faces) if f.selected] + #else: + # meshFaces = map(thickface, me.faces) + + if not meshFaces: + continue + #XXX Window.DrawProgressBar(0.1, 'SmartProj UV Unwrapper, mapping "%s", %i faces.' % (me.name, len(meshFaces))) - - # ======= - # Generate a projection list from face normals, this is ment to be smart :) - - # make a list of face props that are in sync with meshFaces - # Make a Face List that is sorted by area. - # meshFaces = [] - - # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first. - meshFaces.sort( key = lambda a: -a.area ) - - # remove all zero area faces - while meshFaces and meshFaces[-1].area <= SMALL_NUM: - # Set their UV's to 0,0 - for uv in meshFaces[-1].uv: - uv.zero() - meshFaces.pop() - - # Smallest first is slightly more efficient, but if the user cancels early then its better we work on the larger data. - - # Generate Projection Vecs - # 0d is 1.0 - # 180 IS -0.59846 - - - # Initialize projectVecs - if USER_VIEW_INIT: - # Generate Projection - projectVecs = [Vector(Window.GetViewVector()) * ob.matrixWorld.copy().invert().rotationPart()] # We add to this allong the way - else: - projectVecs = [] - - newProjectVec = meshFaces[0].no - newProjectMeshFaces = [] # Popping stuffs it up. - - - # Predent that the most unique angke is ages away to start the loop off - mostUniqueAngle = -1.0 - - # This is popped - tempMeshFaces = meshFaces[:] - - - - # This while only gathers projection vecs, faces are assigned later on. - while 1: - # If theres none there then start with the largest face - - # add all the faces that are close. - for fIdx in range(len(tempMeshFaces)-1, -1, -1): - # Use half the angle limit so we dont overweight faces towards this - # normal and hog all the faces. - if newProjectVec.dot(tempMeshFaces[fIdx].no) > USER_PROJECTION_LIMIT_HALF_CONVERTED: - newProjectMeshFaces.append(tempMeshFaces.pop(fIdx)) - - # Add the average of all these faces normals as a projectionVec - averageVec = Vector(0,0,0) - if USER_AREA_WEIGHT: - for fprop in newProjectMeshFaces: - averageVec += (fprop.no * fprop.area) - else: - for fprop in newProjectMeshFaces: - averageVec += fprop.no - - if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN - projectVecs.append(averageVec.normalize()) - - - # Get the next vec! - # Pick the face thats most different to all existing angles :) - mostUniqueAngle = 1.0 # 1.0 is 0d. no difference. - mostUniqueIndex = 0 # dummy - - for fIdx in range(len(tempMeshFaces)-1, -1, -1): - angleDifference = -1.0 # 180d difference. - - # Get the closest vec angle we are to. - for p in projectVecs: - temp_angle_diff= p.dot(tempMeshFaces[fIdx].no) - - if angleDifference < temp_angle_diff: - angleDifference= temp_angle_diff - - if angleDifference < mostUniqueAngle: - # We have a new most different angle - mostUniqueIndex = fIdx - mostUniqueAngle = angleDifference - - if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED: - #print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces) - # Now weight the vector to all its faces, will give a more direct projection - # if the face its self was not representive of the normal from surrounding faces. - - newProjectVec = tempMeshFaces[mostUniqueIndex].no - newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)] - - - else: - if len(projectVecs) >= 1: # Must have at least 2 projections - break - - - # If there are only zero area faces then its possible - # there are no projectionVecs - if not len(projectVecs): - Draw.PupMenu('error, no projection vecs where generated, 0 area faces can cause this.') - return - - faceProjectionGroupList =[[] for i in range(len(projectVecs)) ] - - # MAP and Arrange # We know there are 3 or 4 faces here - - for fIdx in range(len(meshFaces)-1, -1, -1): - fvec = meshFaces[fIdx].no - i = len(projectVecs) - - # Initialize first - bestAng = fvec.dot(projectVecs[0]) - bestAngIdx = 0 - - # Cycle through the remaining, first alredy done - while i-1: - i-=1 - - newAng = fvec.dot(projectVecs[i]) - if newAng > bestAng: # Reverse logic for dotvecs - bestAng = newAng - bestAngIdx = i - - # Store the area for later use. - faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx]) - - # Cull faceProjectionGroupList, - - - # Now faceProjectionGroupList is full of faces that face match the project Vecs list - for i in range(len(projectVecs)): - # Account for projectVecs having no faces. - if not faceProjectionGroupList[i]: - continue - - # Make a projection matrix from a unit length vector. - MatProj = VectoMat(projectVecs[i]) - - # Get the faces UV's from the projected vertex. - for f in faceProjectionGroupList[i]: - f_uv = f.uv - for j, v in enumerate(f.v): - # XXX - note, between Mathutils in 2.4 and 2.5 the order changed. - f_uv[j][:] = (v.co * MatProj)[:2] - - - if USER_SHARE_SPACE: - # Should we collect and pack later? - islandList = getUvIslands(faceProjectionGroupList, me) - collected_islandList.extend(islandList) - - else: - # Should we pack the islands for this 1 object? - islandList = getUvIslands(faceProjectionGroupList, me) - packIslands(islandList) - - - # update the mesh here if we need to. - - # We want to pack all in 1 go, so pack now - if USER_SHARE_SPACE: + + # ======= + # Generate a projection list from face normals, this is ment to be smart :) + + # make a list of face props that are in sync with meshFaces + # Make a Face List that is sorted by area. + # meshFaces = [] + + # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first. + meshFaces.sort( key = lambda a: -a.area ) + + # remove all zero area faces + while meshFaces and meshFaces[-1].area <= SMALL_NUM: + # Set their UV's to 0,0 + for uv in meshFaces[-1].uv: + uv.zero() + meshFaces.pop() + + # Smallest first is slightly more efficient, but if the user cancels early then its better we work on the larger data. + + # Generate Projection Vecs + # 0d is 1.0 + # 180 IS -0.59846 + + + # Initialize projectVecs + if USER_VIEW_INIT: + # Generate Projection + projectVecs = [Vector(Window.GetViewVector()) * ob.matrixWorld.copy().invert().rotationPart()] # We add to this allong the way + else: + projectVecs = [] + + newProjectVec = meshFaces[0].no + newProjectMeshFaces = [] # Popping stuffs it up. + + + # Predent that the most unique angke is ages away to start the loop off + mostUniqueAngle = -1.0 + + # This is popped + tempMeshFaces = meshFaces[:] + + + + # This while only gathers projection vecs, faces are assigned later on. + while 1: + # If theres none there then start with the largest face + + # add all the faces that are close. + for fIdx in range(len(tempMeshFaces)-1, -1, -1): + # Use half the angle limit so we dont overweight faces towards this + # normal and hog all the faces. + if newProjectVec.dot(tempMeshFaces[fIdx].no) > USER_PROJECTION_LIMIT_HALF_CONVERTED: + newProjectMeshFaces.append(tempMeshFaces.pop(fIdx)) + + # Add the average of all these faces normals as a projectionVec + averageVec = Vector(0,0,0) + if USER_AREA_WEIGHT: + for fprop in newProjectMeshFaces: + averageVec += (fprop.no * fprop.area) + else: + for fprop in newProjectMeshFaces: + averageVec += fprop.no + + if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN + projectVecs.append(averageVec.normalize()) + + + # Get the next vec! + # Pick the face thats most different to all existing angles :) + mostUniqueAngle = 1.0 # 1.0 is 0d. no difference. + mostUniqueIndex = 0 # dummy + + for fIdx in range(len(tempMeshFaces)-1, -1, -1): + angleDifference = -1.0 # 180d difference. + + # Get the closest vec angle we are to. + for p in projectVecs: + temp_angle_diff= p.dot(tempMeshFaces[fIdx].no) + + if angleDifference < temp_angle_diff: + angleDifference= temp_angle_diff + + if angleDifference < mostUniqueAngle: + # We have a new most different angle + mostUniqueIndex = fIdx + mostUniqueAngle = angleDifference + + if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED: + #print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces) + # Now weight the vector to all its faces, will give a more direct projection + # if the face its self was not representive of the normal from surrounding faces. + + newProjectVec = tempMeshFaces[mostUniqueIndex].no + newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)] + + + else: + if len(projectVecs) >= 1: # Must have at least 2 projections + break + + + # If there are only zero area faces then its possible + # there are no projectionVecs + if not len(projectVecs): + Draw.PupMenu('error, no projection vecs where generated, 0 area faces can cause this.') + return + + faceProjectionGroupList =[[] for i in range(len(projectVecs)) ] + + # MAP and Arrange # We know there are 3 or 4 faces here + + for fIdx in range(len(meshFaces)-1, -1, -1): + fvec = meshFaces[fIdx].no + i = len(projectVecs) + + # Initialize first + bestAng = fvec.dot(projectVecs[0]) + bestAngIdx = 0 + + # Cycle through the remaining, first alredy done + while i-1: + i-=1 + + newAng = fvec.dot(projectVecs[i]) + if newAng > bestAng: # Reverse logic for dotvecs + bestAng = newAng + bestAngIdx = i + + # Store the area for later use. + faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx]) + + # Cull faceProjectionGroupList, + + + # Now faceProjectionGroupList is full of faces that face match the project Vecs list + for i in range(len(projectVecs)): + # Account for projectVecs having no faces. + if not faceProjectionGroupList[i]: + continue + + # Make a projection matrix from a unit length vector. + MatProj = VectoMat(projectVecs[i]) + + # Get the faces UV's from the projected vertex. + for f in faceProjectionGroupList[i]: + f_uv = f.uv + for j, v in enumerate(f.v): + # XXX - note, between Mathutils in 2.4 and 2.5 the order changed. + f_uv[j][:] = (v.co * MatProj)[:2] + + + if USER_SHARE_SPACE: + # Should we collect and pack later? + islandList = getUvIslands(faceProjectionGroupList, me) + collected_islandList.extend(islandList) + + else: + # Should we pack the islands for this 1 object? + islandList = getUvIslands(faceProjectionGroupList, me) + packIslands(islandList) + + + # update the mesh here if we need to. + + # We want to pack all in 1 go, so pack now + if USER_SHARE_SPACE: #XXX Window.DrawProgressBar(0.9, "Box Packing for all objects...") - packIslands(collected_islandList) - - print("Smart Projection time: %.2f" % (time.time() - time1)) - # Window.DrawProgressBar(0.9, "Smart Projections done, time: %.2f sec." % (time.time() - time1)) - - if is_editmode: - bpy.ops.object.mode_set(mode='EDIT') - + packIslands(collected_islandList) + + print("Smart Projection time: %.2f" % (time.time() - time1)) + # Window.DrawProgressBar(0.9, "Smart Projections done, time: %.2f sec." % (time.time() - time1)) + + if is_editmode: + bpy.ops.object.mode_set(mode='EDIT') + #XXX Window.DrawProgressBar(1.0, "") #XXX Window.WaitCursor(0) #XXX Window.RedrawAll() """ - pup_block = [\ - 'Projection',\ + pup_block = [\ + 'Projection',\ * ('Angle Limit:', USER_PROJECTION_LIMIT, 1, 89, ''),\ - ('Selected Faces Only', USER_ONLY_SELECTED_FACES, 'Use only selected faces from all selected meshes.'),\ - ('Init from view', USER_VIEW_INIT, 'The first projection will be from the view vector.'),\ - ('Area Weight', USER_AREA_WEIGHT, 'Weight projections vector by face area.'),\ - '',\ - '',\ - '',\ - 'UV Layout',\ - ('Share Tex Space', USER_SHARE_SPACE, 'Objects Share texture space, map all objects into 1 uvmap.'),\ - ('Stretch to bounds', USER_STRETCH_ASPECT, 'Stretch the final output to texture bounds.'),\ + ('Selected Faces Only', USER_ONLY_SELECTED_FACES, 'Use only selected faces from all selected meshes.'),\ + ('Init from view', USER_VIEW_INIT, 'The first projection will be from the view vector.'),\ + ('Area Weight', USER_AREA_WEIGHT, 'Weight projections vector by face area.'),\ + '',\ + '',\ + '',\ + 'UV Layout',\ + ('Share Tex Space', USER_SHARE_SPACE, 'Objects Share texture space, map all objects into 1 uvmap.'),\ + ('Stretch to bounds', USER_STRETCH_ASPECT, 'Stretch the final output to texture bounds.'),\ * ('Island Margin:', USER_ISLAND_MARGIN, 0.0, 0.5, ''),\ - 'Fill in empty areas',\ - ('Fill Holes', USER_FILL_HOLES, 'Fill in empty areas reduced texture waistage (slow).'),\ - ('Fill Quality:', USER_FILL_HOLES_QUALITY, 1, 100, 'Depends on fill holes, how tightly to fill UV holes, (higher is slower)'),\ - ] + 'Fill in empty areas',\ + ('Fill Holes', USER_FILL_HOLES, 'Fill in empty areas reduced texture waistage (slow).'),\ + ('Fill Quality:', USER_FILL_HOLES_QUALITY, 1, 100, 'Depends on fill holes, how tightly to fill UV holes, (higher is slower)'),\ + ] """ from bpy.props import * class SmartProject(bpy.types.Operator): - '''This script projection unwraps the selected faces of a mesh. it operates on all selected mesh objects, and can be used unwrap selected faces, or all faces.''' - bl_idname = "uv.smart_project" - bl_label = "Smart UV Project" + '''This script projection unwraps the selected faces of a mesh. it operates on all selected mesh objects, and can be used unwrap selected faces, or all faces.''' + bl_idname = "uv.smart_project" + bl_label = "Smart UV Project" - bl_register = True - bl_undo = True + bl_register = True + bl_undo = True - angle_limit = FloatProperty(name="Angle Limit", - description="lower for more projection groups, higher for less distortion.", - default=66.0, min=1.0, max=89.0) + angle_limit = FloatProperty(name="Angle Limit", + description="lower for more projection groups, higher for less distortion.", + default=66.0, min=1.0, max=89.0) - island_margin = FloatProperty(name="Island Margin", - description="Margin to reduce bleed from adjacent islands.", - default=0.0, min=0.0, max=1.0) + island_margin = FloatProperty(name="Island Margin", + description="Margin to reduce bleed from adjacent islands.", + default=0.0, min=0.0, max=1.0) - def poll(self, context): - return context.active_object != None + def poll(self, context): + return context.active_object != None - def execute(self, context): - main(context, self.properties.island_margin, self.properties.angle_limit) - return ('FINISHED',) + def execute(self, context): + main(context, self.properties.island_margin, self.properties.angle_limit) + return ('FINISHED',) bpy.ops.add(SmartProject) @@ -1137,10 +1137,10 @@ bpy.ops.add(SmartProject) import dynamic_menu menu_func = (lambda self, context: self.layout.operator(SmartProject.bl_idname, - text="Smart Project")) + text="Smart Project")) menu_item = dynamic_menu.add(bpy.types.VIEW3D_MT_uv_map, menu_func) if __name__ == '__main__': - bpy.ops.uv.smart_project() + bpy.ops.uv.smart_project() diff --git a/release/scripts/op/wm.py b/release/scripts/op/wm.py index f93c0d47e28..c5fc18964bf 100644 --- a/release/scripts/op/wm.py +++ b/release/scripts/op/wm.py @@ -33,7 +33,7 @@ class MESH_OT_delete_edgeloop(bpy.types.Operator): bpy.ops.tfm.edge_slide(value=1.0) bpy.ops.mesh.select_more() bpy.ops.mesh.remove_doubles() - + return ('FINISHED',) rna_path_prop = StringProperty(name="Context Attributes", diff --git a/release/scripts/ui/properties_data_bone.py b/release/scripts/ui/properties_data_bone.py index 2c47ac03d7d..4a10ff80a32 100644 --- a/release/scripts/ui/properties_data_bone.py +++ b/release/scripts/ui/properties_data_bone.py @@ -193,6 +193,7 @@ class BONE_PT_relations(BoneButtonsPanel): sub.active = (not bone.parent or not bone.connected) sub.prop(bone, "local_location", text="Local Location") + class BONE_PT_display(BoneButtonsPanel): bl_label = "Display" diff --git a/release/scripts/ui/properties_material.py b/release/scripts/ui/properties_material.py index 0f3221254cc..eb2a73d1790 100644 --- a/release/scripts/ui/properties_material.py +++ b/release/scripts/ui/properties_material.py @@ -481,7 +481,7 @@ class MATERIAL_PT_sss(MaterialButtonsPanel): mat = active_node_mat(context.material) sss = mat.subsurface_scattering wide_ui = context.region.width > narrowui - + layout.active = (sss.enabled) and (not mat.shadeless) row = layout.row().split() diff --git a/release/scripts/ui/properties_object_constraint.py b/release/scripts/ui/properties_object_constraint.py index d3bad4e7bdb..8a1d26518fe 100644 --- a/release/scripts/ui/properties_object_constraint.py +++ b/release/scripts/ui/properties_object_constraint.py @@ -21,6 +21,7 @@ import bpy narrowui = 180 + class ConstraintButtonsPanel(bpy.types.Panel): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' diff --git a/release/scripts/ui/properties_physics_cloth.py b/release/scripts/ui/properties_physics_cloth.py index d483bf8f804..0829b533c81 100644 --- a/release/scripts/ui/properties_physics_cloth.py +++ b/release/scripts/ui/properties_physics_cloth.py @@ -28,7 +28,7 @@ from properties_physics_common import effector_weights_ui def cloth_panel_enabled(md): return md.point_cache.baked is False - + class CLOTH_MT_presets(bpy.types.Menu): ''' @@ -227,7 +227,7 @@ class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel): def draw(self, context): cloth = context.cloth.settings effector_weights_ui(self, context, cloth.effector_weights) - + bpy.types.register(CLOTH_MT_presets) bpy.types.register(PHYSICS_PT_cloth) diff --git a/release/scripts/ui/properties_render.py b/release/scripts/ui/properties_render.py index 3f176e965b4..35f52552e6b 100644 --- a/release/scripts/ui/properties_render.py +++ b/release/scripts/ui/properties_render.py @@ -401,8 +401,8 @@ class RENDER_PT_encoding(RenderButtonsPanel): col.label(text="Mux:") col.prop(rd, "ffmpeg_muxrate", text="Rate") col.prop(rd, "ffmpeg_packetsize", text="Packet Size") - - # Audio: + + # Audio: layout.prop(rd, "ffmpeg_multiplex_audio", text="Audio") sub = layout.column() @@ -554,4 +554,4 @@ bpy.types.register(RENDER_PT_output) bpy.types.register(RENDER_PT_encoding) bpy.types.register(RENDER_PT_performance) bpy.types.register(RENDER_PT_post_processing) -bpy.types.register(RENDER_PT_stamp) \ No newline at end of file +bpy.types.register(RENDER_PT_stamp) diff --git a/release/scripts/ui/space_image.py b/release/scripts/ui/space_image.py index 44a90c084d0..32c5dbb9375 100644 --- a/release/scripts/ui/space_image.py +++ b/release/scripts/ui/space_image.py @@ -149,14 +149,15 @@ class IMAGE_MT_uvs_transform(bpy.types.Menu): layout.operator("tfm.translate") layout.operator("tfm.rotate") layout.operator("tfm.resize") - + + class IMAGE_MT_uvs_snap(bpy.types.Menu): bl_label = "Snap" - def draw(self, context): + def draw(self, context): layout = self.layout layout.operator_context = 'EXEC_REGION_WIN' - + layout.operator("uv.snap_selection", text="Selected to Pixels").target = 'PIXELS' layout.operator("uv.snap_selection", text="Selected to Cursor").target = 'CURSOR' layout.operator("uv.snap_selection", text="Selected to Adjacent Unselected").target = 'ADJACENT_UNSELECTED' @@ -166,6 +167,7 @@ class IMAGE_MT_uvs_snap(bpy.types.Menu): layout.operator("uv.snap_cursor", text="Cursor to Pixels").target = 'PIXELS' layout.operator("uv.snap_cursor", text="Cursor to Selection").target = 'SELECTION' + class IMAGE_MT_uvs_mirror(bpy.types.Menu): bl_label = "Mirror" diff --git a/release/scripts/ui/space_sequencer.py b/release/scripts/ui/space_sequencer.py index 8ac77a50d55..56f5aa883c8 100644 --- a/release/scripts/ui/space_sequencer.py +++ b/release/scripts/ui/space_sequencer.py @@ -522,7 +522,7 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel): row.prop(strip.sound, "caching") layout.prop(strip, "volume") - + class SEQUENCER_PT_scene(SequencerButtonsPanel): bl_label = "Scene" @@ -541,7 +541,7 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel): layout = self.layout strip = act_strip(context) - + layout.template_ID(strip, "scene") diff --git a/release/scripts/ui/space_text.py b/release/scripts/ui/space_text.py index f3e0dbb57c4..6ea499704fc 100644 --- a/release/scripts/ui/space_text.py +++ b/release/scripts/ui/space_text.py @@ -168,7 +168,6 @@ class TEXT_MT_templates(bpy.types.Menu): bl_label = "Script Templates" def draw(self, context): - import os self.path_menu(bpy.utils.script_paths("templates"), "text.open") diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py index 34669e14859..32a9f0d2534 100644 --- a/release/scripts/ui/space_userpref.py +++ b/release/scripts/ui/space_userpref.py @@ -1465,4 +1465,4 @@ bpy.ops.add(WM_OT_keyconfig_export) bpy.ops.add(WM_OT_keymap_edit) bpy.ops.add(WM_OT_keymap_restore) bpy.ops.add(WM_OT_keyitem_add) -bpy.ops.add(WM_OT_keyitem_remove) \ No newline at end of file +bpy.ops.add(WM_OT_keyitem_remove) diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py index 72191e822ee..8de29dc30ff 100644 --- a/release/scripts/ui/space_view3d.py +++ b/release/scripts/ui/space_view3d.py @@ -30,7 +30,7 @@ class VIEW3D_HT_header(bpy.types.Header): # view = context.space_data mode_string = context.mode edit_object = context.edit_object - object = context.active_object + obj = context.active_object toolsettings = context.scene.tool_settings row = layout.row(align=True) @@ -48,7 +48,7 @@ class VIEW3D_HT_header(bpy.types.Header): if edit_object: sub.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower()) - elif object: + elif obj: if mode_string not in ['PAINT_WEIGHT', 'PAINT_TEXTURE']: sub.menu("VIEW3D_MT_%s" % mode_string.lower()) else: @@ -57,7 +57,7 @@ class VIEW3D_HT_header(bpy.types.Header): layout.template_header_3D() # Proportional editing - if object.mode in ('OBJECT', 'EDIT'): + if obj.mode in ('OBJECT', 'EDIT'): row = layout.row(align=True) row.prop(toolsettings, "proportional_editing", text="", icon_only=True) if toolsettings.proportional_editing != 'DISABLED': @@ -69,7 +69,7 @@ class VIEW3D_HT_header(bpy.types.Header): row.prop(toolsettings, "snap_element", text="", icon_only=True) if toolsettings.snap_element != 'INCREMENT': row.prop(toolsettings, "snap_target", text="", icon_only=True) - if object.mode == 'OBJECT': + if obj.mode == 'OBJECT': row.prop(toolsettings, "snap_align_rotation", text="") if toolsettings.snap_element == 'VOLUME': row.prop(toolsettings, "snap_peel_object", text="") @@ -83,7 +83,7 @@ class VIEW3D_HT_header(bpy.types.Header): props.animation = True # Pose - if object.mode == 'POSE': + if obj.mode == 'POSE': row = layout.row(align=True) row.operator("pose.copy", text="", icon='ICON_COPYDOWN') row.operator("pose.paste", text="", icon='ICON_PASTEDOWN') @@ -114,16 +114,16 @@ class VIEW3D_MT_transform(bpy.types.Menu): # TODO: get rid of the custom text strings? def draw(self, context): layout = self.layout - + layout.operator("tfm.translate", text="Grab/Move") # TODO: sub-menu for grab per axis layout.operator("tfm.rotate", text="Rotate") # TODO: sub-menu for rot per axis layout.operator("tfm.resize", text="Scale") # TODO: sub-menu for scale per axis - + layout.separator() - + layout.operator("tfm.tosphere", text="To Sphere") layout.operator("tfm.shear", text="Shear") layout.operator("tfm.warp", text="Warp") @@ -133,15 +133,16 @@ class VIEW3D_MT_transform(bpy.types.Menu): else: layout.operator_context = 'EXEC_AREA' layout.operator("tfm.transform", text="Align to Transform Orientation").mode = 'ALIGN' # XXX see alignmenu() in edit.c of b2.4x to get this working - + layout.separator() - + layout.operator_context = 'EXEC_AREA' - + layout.operator("object.center_set", text="ObData to Centroid").type = 'CENTER' layout.operator("object.center_set", text="Centroid to ObData").type = 'CENTER_NEW' layout.operator("object.center_set", text="Centroid to 3D Cursor").type = 'CENTER_CURSOR' - + + class VIEW3D_MT_mirror(bpy.types.Menu): bl_label = "Mirror" @@ -149,11 +150,11 @@ class VIEW3D_MT_mirror(bpy.types.Menu): layout = self.layout layout.operator("tfm.mirror", text="Interactive Mirror") - + layout.separator() - + layout.operator_context = 'INVOKE_REGION_WIN' - + props = layout.operator("tfm.mirror", text="X Global") props.constraint_axis = (True, False, False) props.constraint_orientation = 'GLOBAL' @@ -163,10 +164,10 @@ class VIEW3D_MT_mirror(bpy.types.Menu): props = layout.operator("tfm.mirror", text="Z Global") props.constraint_axis = (False, False, True) props.constraint_orientation = 'GLOBAL' - + if context.edit_object: layout.separator() - + props = layout.operator("tfm.mirror", text="X Local") props.constraint_axis = (True, False, False) props.constraint_orientation = 'LOCAL' @@ -176,7 +177,8 @@ class VIEW3D_MT_mirror(bpy.types.Menu): props = layout.operator("tfm.mirror", text="Z Local") props.constraint_axis = (False, False, True) props.constraint_orientation = 'LOCAL' - + + class VIEW3D_MT_snap(bpy.types.Menu): bl_label = "Snap" @@ -594,7 +596,7 @@ class VIEW3D_MT_select_face(bpy.types.Menu):# XXX no matching enum def draw(self, context): layout = self.layout - + # TODO # see view3d_select_faceselmenu @@ -785,7 +787,7 @@ class VIEW3D_MT_hook(bpy.types.Menu): layout.operator_context = 'EXEC_AREA' layout.operator("object.hook_add_newob") layout.operator("object.hook_add_selob") - + if [mod.type == 'HOOK' for mod in context.active_object.modifiers]: layout.separator() layout.operator_menu_enum("object.hook_assign", "modifier") @@ -803,7 +805,7 @@ class VIEW3D_MT_vertex_group(bpy.types.Menu): layout = self.layout layout.operator_context = 'EXEC_AREA' layout.operator("object.vertex_group_assign", text="Assign to New Group").new = True - + ob = context.active_object if ob.mode == 'EDIT': if ob.vertex_groups and ob.active_vertex_group: @@ -812,7 +814,7 @@ class VIEW3D_MT_vertex_group(bpy.types.Menu): layout.operator("object.vertex_group_remove_from", text="Remove from Active Group") layout.operator("object.vertex_group_remove_from", text="Remove from All").all = True layout.separator() - + if ob.vertex_groups and ob.active_vertex_group: layout.operator_menu_enum("object.vertex_group_set_active", "group", text="Set Active Group") layout.operator("object.vertex_group_remove", text="Remove Active Group") @@ -898,7 +900,7 @@ class VIEW3D_MT_pose(bpy.types.Menu): layout = self.layout arm = context.active_object.data - + layout.menu("VIEW3D_MT_transform") layout.menu("VIEW3D_MT_snap") if arm.drawtype in ('BBONE', 'ENVELOPE'): @@ -1238,7 +1240,7 @@ def draw_curve(self, context): layout = self.layout settings = context.tool_settings - + layout.menu("VIEW3D_MT_transform") layout.menu("VIEW3D_MT_mirror") layout.menu("VIEW3D_MT_snap") @@ -1374,7 +1376,7 @@ class VIEW3D_MT_edit_meta(bpy.types.Menu): layout.operator("ed.redo") layout.separator() - + layout.menu("VIEW3D_MT_transform") layout.menu("VIEW3D_MT_mirror") layout.menu("VIEW3D_MT_snap") @@ -1412,7 +1414,7 @@ class VIEW3D_MT_edit_lattice(bpy.types.Menu): layout = self.layout settings = context.tool_settings - + layout.menu("VIEW3D_MT_transform") layout.menu("VIEW3D_MT_mirror") layout.menu("VIEW3D_MT_snap") @@ -1435,7 +1437,7 @@ class VIEW3D_MT_edit_armature(bpy.types.Menu): edit_object = context.edit_object arm = edit_object.data - + layout.menu("VIEW3D_MT_transform") layout.menu("VIEW3D_MT_mirror") layout.menu("VIEW3D_MT_snap") @@ -1562,11 +1564,7 @@ class VIEW3D_PT_3dview_properties(bpy.types.Panel): col.prop(view, "clip_start", text="Start") col.prop(view, "clip_end", text="End") - - layout.column().prop(scene, "cursor_location", text="3D Cursor:") - - class VIEW3D_PT_3dview_name(bpy.types.Panel): @@ -1609,7 +1607,7 @@ class VIEW3D_PT_3dview_display(bpy.types.Panel): view = context.space_data gs = context.scene.game_data ob = context.object - + col = layout.column() col.prop(view, "display_x_axis", text="X Axis") col.prop(view, "display_y_axis", text="Y Axis") @@ -1620,7 +1618,7 @@ class VIEW3D_PT_3dview_display(bpy.types.Panel): if ob and ob.type == 'MESH': mesh = ob.data col.prop(mesh, "all_edges") - + col = layout.column() col.prop(view, "display_floor", text="Grid Floor") sub = col.column(align=True) @@ -1628,7 +1626,7 @@ class VIEW3D_PT_3dview_display(bpy.types.Panel): sub.prop(view, "grid_lines", text="Lines") sub.prop(view, "grid_spacing", text="Spacing") sub.prop(view, "grid_subdivisions", text="Subdivisions") - + col = layout.column() col.label(text="Shading:") col.prop(gs, "material_mode", text="") @@ -1826,7 +1824,7 @@ class VIEW3D_PT_context_properties(bpy.types.Panel): return "object" return "" - + def poll(self, context): member = self._active_context_member(context) if member: @@ -1845,46 +1843,6 @@ class VIEW3D_PT_context_properties(bpy.types.Panel): rna_prop_ui.draw(self.layout, context, member, False) -# Operators -from bpy.props import * - - -class OBJECT_OT_select_pattern(bpy.types.Operator): - '''Select object matching a naming pattern.''' - bl_idname = "object.select_pattern" - bl_label = "Select Pattern" - bl_register = True - bl_undo = True - - pattern = StringProperty(name="Pattern", description="Name filter using '*' and '?' wildcard chars", maxlen=32, default="*") - case_sensitive = BoolProperty(name="Case Sensitive", description="Do a case sensitive compare", default=False) - extend = BoolProperty(name="Extend", description="Extend the existing selection", default=True) - - def execute(self, context): - - import fnmatch - - if self.properties.case_sensitive: - pattern_match = fnmatch.fnmatchcase - else: - pattern_match = lambda a, b: fnmatch.fnmatchcase(a.upper(), b.upper()) - - for ob in context.visible_objects: - if pattern_match(ob.name, self.properties.pattern): - ob.selected = True - elif not self.properties.extend: - ob.selected = False - - return ('FINISHED',) - - # TODO - python cant do popups yet - ''' - def invoke(self, context, event): - wm = context.manager - wm.add_fileselect(self) - return ('RUNNING_MODAL',) - ''' - bpy.types.register(VIEW3D_HT_header) # Header bpy.types.register(VIEW3D_MT_view) #View Menus @@ -1979,5 +1937,3 @@ bpy.types.register(VIEW3D_PT_transform_orientations) bpy.types.register(VIEW3D_PT_etch_a_ton) bpy.types.register(VIEW3D_PT_context_properties) - -bpy.ops.add(OBJECT_OT_select_pattern) diff --git a/release/scripts/ui/space_view3d_toolbar.py b/release/scripts/ui/space_view3d_toolbar.py index 533ff496c08..fe267c725a2 100644 --- a/release/scripts/ui/space_view3d_toolbar.py +++ b/release/scripts/ui/space_view3d_toolbar.py @@ -171,7 +171,7 @@ class VIEW3D_PT_tools_curveedit(View3DPanel): col.operator("tfm.translate") col.operator("tfm.rotate") col.operator("tfm.resize", text="Scale") - + col = layout.column(align=True) col.operator("tfm.transform", text="Tilt").mode = 'TILT' col.operator("tfm.transform", text="Shrink/Fatten").mode = 'CURVE_SHRINKFATTEN'