This allows you to explicitly control the render order with the fixed bin and other bins of the same type. It allows you to place nodepaths before/after each other. Where it really helps though is in the group interface. It will let you specify a render order for a particular set of nodes and then set the render order for them as a block with respect to other nodes. Groups can contain other groups as well as nodes, and groups can be modified at runtime and the render order will correct itself.
This is useful for GUI’s–it makes sure the render order of frames and buttons and whatever else is correct (note that the direct gui sort of does this already). I have been using it with both my custom gui stuff and with the overlays by davedes. I thought it might be useful here as it fills a gap in the bin and render order design.
from random import uniform
class binOrder(object):
def __init__(self,bin='fixed',startingIndex=0):
self.bin = bin
self.startingIndex = startingIndex
self.groups = {'mainOrder':[]}
def createGroup(self,name,*nodes):
'''the nodes passed in are rendered in back to front order based upon the order of being passed in.
can pass in a list of nodes and/or other group names
You can use the name to move the group around in the render order
the name must be unique or it will overwrite the existing group with that name.
'' means a random one will be generated'''
if name=='': name = str(id(nodes)+uniform(0,9999))
self.groups[name] = self._determineArgs(nodes)[:] #make a copy of the list so that if it
#changes this doesn't change. fixes a nasty intermittent bug
#where changing that list messes up this class
return name
'''all of these insert/move functions accept the node to reference. This can be a group name or a node
already in the ordering system. A value of None anywhere will render the node in front of everything.
The nodes can be a list of nodes and/or group names. movingNode has to be one node or group name'''
def addToGroup(self,group,*nodes):
self.groups[group].extend(self._determineArgs(nodes))
def insertInFront(self,node,*nodes):
group,index = self._findPlace(node)
if group==None: return
self.groups[group][index+1:index+1] = self._determineArgs(nodes)
self._updateOrder()
def insertInBack(self,node,*nodes):
group,index = self._findPlace(node)
if group==None: return
self.groups[group][index:index] = self._determineArgs(nodes)
self._updateOrder()
def bringToFront(self,movingNode,group=None):
oldGroup,oldIndex = self._findPlace(movingNode)
if oldGroup==None: return
self.groups[oldGroup].pop(oldIndex)
if group==None: group='mainOrder'
self.groups[group].append(movingNode)
self._updateOrder()
def moveInFront(self,node,movingNode):
oldGroup,oldIndex = self._findPlace(movingNode)
if oldGroup==None: return
self.groups[oldGroup].pop(oldIndex)
group,index = self._findPlace(node)
if group==None: return
self.groups[group][index+1:index+1] = [movingNode]
self._updateOrder()
def moveInBack(self,node,movingNode):
oldGroup,oldIndex = self._findPlace(movingNode)
if oldGroup==None: return
self.groups[oldGroup].pop(oldIndex)
group,index = self._findPlace(node)
if group==None: return
self.groups[group][index:index] = [movingNode]
self._updateOrder()
def remove(self,node):
'''removes the node/group from the ordering system, but does not delete groups from memory--still there just insert again'''
group,index = self._findPlace(node)
if group==None: return
self.groups[group].pop(index)
self._updateOrder()
def removeGroup(self,node):
'''same as remove, but will delete the group from the list too'''
group,index = self._findPlace(node)
if group==None: return
self.groups[group].pop(index)
if isinstance(node,str): #clean up the group too.
del self.groups[node]
self._updateOrder()
def _updateOrder(self,group=None,num=None):
'''actually updates the order. recursive'''
if group==None: group = 'mainOrder'
if num==None: num = self.startingIndex
for node in self.groups[group]:
if isinstance(node,str): #another group
num = self._updateOrder(node,num)
else:
node.setBin(self.bin,num)
num+=1
return num
def _findPlace(self,node):
'finds where the supplied node is, returns the name of the group and the index'
if node==None:
return ['mainOrder',len(self.groups['mainOrder'])]
for name,group in self.groups.iteritems():
try:
return [name,group.index(node)]
except ValueError:
pass
return [None,0]
def _determineArgs(self,nodes):
nodes = list(nodes)
if len(nodes)==0: return []
if len(nodes)>1: return nodes
if hasattr(nodes[0],'__iter__') and not isinstance(nodes[0],str):
return nodes[0]
return nodes