def visit(self, node): """Visit an individual node, search for self.desiredTypes This is a heavily trimmed version of the superclass method """ todo = [(0, node)] currentStack = [] childrenTypes = TRAVERSAL_TYPES + self.desiredTypes while todo: index, node = todo[0] del todo[0] del currentStack[index:] is_desired = isinstance(node, self.desiredTypes) try: children = self.children(node, types=childrenTypes) except: traceback.print_exc() log.error( """exception in children method for node %s""", node, ) else: stack_length = len(currentStack) new_items = [(stack_length + 1, child) for child in children] if is_desired or new_items: currentStack.append(node) if is_desired: self.result.append( nodepath.NodePath(tuple(currentStack))) if new_items: todo[0:0] = new_items
def __init__(self): """Initialise the visitor object calls self.buildVMethods() then builds the current stack. Attributes: currentStack -- nodepath describing the current processing stack for this visitor _vmethods -- mapping from class/superclass to methods to be applied on entry to any instance of the class, see the vmethods method, (multiple match) """ self.buildVMethods() self.currentStack = nodepath.NodePath()
def integrate(self, node, parentPath=None): """Integrate any children of node which are of interest""" if parentPath is None: parentPath = nodepath.NodePath([]) todo = [(node, parentPath)] while todo: next, parents = todo.pop(0) path = parents + next np = self.npFor(next) np.append(path) if hasattr(next, 'bind'): for context in self.contexts: context = context() if context is not None: next.bind(context) _ = self.npFor(next) for typ in self.INTERESTING_TYPES: if isinstance(next, typ): self.paths.setdefault(typ, []).append(path) if hasattr(next, 'renderedChildren'): # watch for next's changes... for child in next.renderedChildren(): todo.append((child, path))
def __call__( self ): """Render geometry once for each pick-event to be serviced This is the actual implementation of the glSelectBuffer- based selection code. It is fairly standard OpenGL selection code. We take all of the events which have the same picking-point and render them together (since they have the same picking characteristics). For each picking-point, we set up the constrained picking matrix and results array in our ContextSetupDisplay/ PickProjection methods, which are visited by the standard RenderVisitor algorithm. The visiting code, particularly RenderVisitor.Grouping, pushes the appropriate names onto the name stack during rendering, filling the results array as appropriate. After visiting the entire scenegraph, we retrieve the results from the name-stack and dispatch the events to their appropriate handlers. XXX Really the event handling should not be going on here, instead the events should be added to a queue to be processed after the RenderPass has completely finished, and the ContextLock has been released (but the scenegraph lock has been re-acquired). """ if self.shouldDraw( ): client = self.context events = client.getPickEvents().values() client.getPickEvents().clear() pickPoints = {} for event in events: key = tuple(event.getPickPoint()) pickPoints.setdefault( key, []).append( event ) for point, set in pickPoints.items(): self.pickPoint = point self.selectable = {} self.visit( client ) ## following two lines get the results of the render... nameStack = list(glRenderMode(GL_RENDER)) ## and now update the event... for event in set: ##print '%s items rendered'%( len(self.selectable), ) event.setNameStack( nameStack ) event.setObjectPaths([ nodepath.NodePath(filter(None,[ self.selectable.get(long(name)) for name in names ])) for (near,far,names) in nameStack ]) event.modelViewMatrix = self.modelView event.projectionMatrix = self.projection event.viewport = self.viewport if hasattr( client, 'ProcessEvent'): client.ProcessEvent( event ) return self.visible return 0