def depend(self, node, field=None): """Add a dependency on given node's field value source -- the node being watched field -- the field on the node being watched Dependency on the node means that this cache holder will be invalidated if the field value changes. This does not create a dependency on the existence of node, so you should set the dependency for the field holding any nodes which should invalidate this CacheHolder Note: This does not affect any other CacheHolder for our client node. """ if field is not None: if isinstance(field, (bytes, unicode)): field = protofunctions.getField(node, field) self.depend_signal( ('set', field), #signal node, # sender ) self.depend_signal( ('del', field), #signal node, # sender ) self.depend_signal( ('route', field), #signal node, # sender ) else: # dependency on the mere existence of the node self.depend_object(node)
def depend( self, node, field=None ): """Add a dependency on given node's field value source -- the node being watched field -- the field on the node being watched Dependency on the node means that this cache holder will be invalidated if the field value changes. This does not create a dependency on the existence of node, so you should set the dependency for the field holding any nodes which should invalidate this CacheHolder Note: This does not affect any other CacheHolder for our client node. """ if field is not None: if isinstance( field, (bytes,unicode)): field = protofunctions.getField(node, field) self.depend_signal( ('set', field),#signal node, # sender ) self.depend_signal( ('del', field),#signal node, # sender ) self.depend_signal( ('route', field),#signal node, # sender ) else: # dependency on the mere existence of the node self.depend_object( node )
def compile( self, mode=None ): """Compile the box as a display-list""" if vbo.get_implementation(): vb = vbo.VBO( array( list(yieldVertices( self.size )), 'f')) def draw( textured=True,lit=True ): vb.bind() try: glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS) try: glEnableClientState( GL_VERTEX_ARRAY ) if lit: glEnableClientState( GL_NORMAL_ARRAY ) glNormalPointer( GL_FLOAT, 32, vb+8 ) if textured: glEnableClientState( GL_TEXTURE_COORD_ARRAY ) glTexCoordPointer( 2, GL_FLOAT, 32, vb ) glVertexPointer( 3, GL_FLOAT, 32, vb+20 ) glDrawArrays( GL_TRIANGLES, 0, 36 ) finally: glPopClientAttrib() finally: vb.unbind() else: vb = array( list(yieldVertices( self.size )), 'f') def draw(textured=True,lit=True): glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS) try: glInterleavedArrays( GL_T2F_N3F_V3F, 0, vb ) glDrawArrays( GL_TRIANGLES, 0, 36 ) finally: glPopClientAttrib() holder = mode.cache.holder(self, draw) holder.depend( self, protofunctions.getField(self, 'size') ) return draw
def drawTransparent( self, constant, mode=None ): """Fairly complex mechanism for drawing sorted polygons""" # we have to create a temporary array of centres for # each polygon, that requires taking the centres and then # creating an index-set that re-orders the polygons... centers = mode.cache.getData(self, key='centers') if centers is None: ## cache centers for future rendering passes... ordered_points = take( self.coord.point, self.index.astype('i'), 0 ) centers = triangleutilities.centers( ordered_points, vertexCount=self.polygonSides, components = 3, ) holder = mode.cache.holder(self, key = "centers", data = centers) for name in ("polygonSides", "index", "coord"): field = protofunctions.getField( self, name ) holder.depend( self, field ) for (n, attr) in [ (self.coord, 'point'), ]: if n: holder.depend( n, protofunctions.getField( n,attr) ) assert centers is not None # get distances to the viewer centers = polygonsort.distances( centers, modelView = mode.getModelView(), projection = mode.getProjection(), viewport = mode.getViewport(), ) assert len(centers) == len(self.index)//self.polygonSides # get the center indices in sorted order indices = argsort( centers ) sortedIndices = self.index[:] sortedIndices = reshape( sortedIndices, (-1,self.polygonSides)) sortedIndices = take( sortedIndices, indices, 0 ) # okay, now we can render... glDrawElementsui( constant, sortedIndices, )
def drawTransparent(self, constant, mode=None): """Fairly complex mechanism for drawing sorted polygons""" # we have to create a temporary array of centres for # each polygon, that requires taking the centres and then # creating an index-set that re-orders the polygons... centers = mode.cache.getData(self, key='centers') if centers is None: ## cache centers for future rendering passes... ordered_points = take(self.coord.point, self.index.astype('i'), 0) centers = triangleutilities.centers( ordered_points, vertexCount=self.polygonSides, components=3, ) holder = mode.cache.holder(self, key="centers", data=centers) for name in ("polygonSides", "index", "coord"): field = protofunctions.getField(self, name) holder.depend(self, field) for (n, attr) in [ (self.coord, 'point'), ]: if n: holder.depend(n, protofunctions.getField(n, attr)) assert centers is not None # get distances to the viewer centers = polygonsort.distances( centers, modelView=mode.getModelView(), projection=mode.getProjection(), viewport=mode.getViewport(), ) assert len(centers) == len(self.index) // self.polygonSides # get the center indices in sorted order indices = argsort(centers) sortedIndices = self.index[:] sortedIndices = reshape(sortedIndices, (-1, self.polygonSides)) sortedIndices = take(sortedIndices, indices, 0) # okay, now we can render... glDrawElementsui( constant, sortedIndices, )
def buildCacheHolder(self, key="", mode=None): """Get a cache holder with all dependencies set""" holder = mode.cache.holder(self.target, None, key=key) for field in protofunctions.getFields(self.target): # change to any field requires a recompile holder.depend(self.target, field) for (n, attr) in [ (self.target.coord, 'point'), (self.target.color, 'color'), (self.target.texCoord, 'point'), (self.target.normal, 'vector'), ]: if n: holder.depend(n, protofunctions.getField(n, attr)) return holder
def buildCacheHolder( self, key="", mode=None ): """Get a cache holder with all dependencies set""" holder = mode.cache.holder(self.target, None, key=key) for field in protofunctions.getFields( self.target ): # change to any field requires a recompile holder.depend( self.target, field ) for (n, attr) in [ (self.target.coord, 'point'), (self.target.color, 'color'), (self.target.texCoord, 'point'), (self.target.normal, 'vector'), ]: if n: holder.depend( n, protofunctions.getField(n,attr) ) return holder
def Rendering(self, node): """Regular rendering isn't desirable...""" ### should have a way to specify non-occluding geometry... node = node.geometry if not isinstance(node, basenodes.IndexedFaceSet): return cc = indexedfaceset.ArrayGeometryCompiler(node) ag = cc.compile( visible=False, lit=False, textured=False, transparent=False, mode=self, ) if ag is indexedfaceset.DUMMY_RENDER: return None # okay, we have an array-geometry object edgeSet = self.cache.getData(node, self.cacheKey) if not edgeSet: if ag.vertices: edgeSet = edgeset.EdgeSet( points=ag.vertices.data, ccw=ag.ccw == GL_CCW, ) holder = self.cache.holder( client=node, key=self.cacheKey, data=edgeSet, ) for (n, attr) in [ (node, 'coordIndex'), (node, 'ccw'), (node.coord, 'point'), ]: if n: holder.depend(n, protofunctions.getField(n, attr)) else: edgeSet = None if not edgeSet: return # okay, we have an edge-set object... volume = edgeSet.volume(self.currentLight, self.currentStack) if not volume: return # now we have a shadow-volume for this light and edge-set volume.render(self)
def cacheVolume(node, volume, nodeFieldPairs=()): """Cache bounding volume for the given node node -- the node associated with the volume volume -- the BoundingVolume object to be cached nodeFieldPairs -- set of (node,fieldName) tuples giving the dependencies for the volume. Should normally include the node itself. If fieldName is None a dependency is created on the node itself. """ holder = cache.CACHE.holder(node, key="boundingVolume", data=volume) for (n, attr) in nodeFieldPairs: if n: if attr is not None: holder.depend(n, protofunctions.getField(n, attr)) else: holder.depend(n, None) return volume
def addRoute(self, route, *args): '''Add a route to the scenegraph route,args -- Possible forms: ROUTE object -- added to routes ((source)node,field,(destination)node,field) -- ROUTE created, nodes may be strings, in which case getDEF( node ) is called for each ((source)node,field,target( signal, sender, value )) -- field.watch( target ) is called for the source node (which can be a DEF name). ''' if args: route = (route,) + args if isinstance( route, (tuple,list)): if len(route) == 4: # 4-element route definition, e.g. from strings... from vrml.route import ROUTE source,sourceField,destination,destinationField = route if isinstance( source, (str,unicode)): source = self.getDEF( source ) if isinstance( destination, (str,unicode)): destination = self.getDEF( destination ) route = ROUTE( source = source, sourceField = sourceField, destination = destination, destinationField = destinationField, ) elif len(route) == 3: # 2-element source plus a function to receive... source,sourceField,target = route if not callable( target ): raise TypeError( """Need a callable target object!""" ) if isinstance( source, (str,unicode)): source = self.getDEF( source ) field = protofunctions.getField( source, sourceField ) field.watch( source, target, ('set',field) ) field.watch( source, target, ('del',field) ) self.routes.append( route ) return route
def Rendering( self, node ): """Regular rendering isn't desirable...""" ### should have a way to specify non-occluding geometry... node = node.geometry if not isinstance( node, basenodes.IndexedFaceSet ): return cc = indexedfaceset.ArrayGeometryCompiler( node ) ag = cc.compile( visible=False,lit=False,textured=False,transparent=False, mode = self, ) if ag is indexedfaceset.DUMMY_RENDER: return None # okay, we have an array-geometry object edgeSet = self.cache.getData(node,self.cacheKey) if not edgeSet: if ag.vertices: edgeSet = edgeset.EdgeSet( points = ag.vertices.data, ccw = ag.ccw == GL_CCW, ) holder = self.cache.holder( client = node, key = self.cacheKey, data = edgeSet, ) for (n, attr) in [ (node, 'coordIndex'), (node, 'ccw'), (node.coord, 'point'), ]: if n: holder.depend( n, protofunctions.getField(n,attr) ) else: edgeSet = None if not edgeSet: return # okay, we have an edge-set object... volume = edgeSet.volume( self.currentLight, self.currentStack ) if not volume: return # now we have a shadow-volume for this light and edge-set volume.render( self )
def _bind( self, source, field ): """Low-level binding of the source,field key This method allows sub-classes to do multiple bindings when bind() is called. """ if source and field: try: sf = protofunctions.getField( source, field ) except (AttributeError, KeyError): print("""%s: field %s doesn't exist on %s"""%(protofunctions.protoName(self), field, source)) else: for message in ('set','del','route'): dispatcher.connect( receiver = self.forward, sender = source, signal = (message,sf), ) else: print("""NULL ROUTE bound""", self)
def _bind(self, source, field): """Low-level binding of the source,field key This method allows sub-classes to do multiple bindings when bind() is called. """ if source and field: try: sf = protofunctions.getField(source, field) except (AttributeError, KeyError): print("""%s: field %s doesn't exist on %s""" % (protofunctions.protoName(self), field, source)) else: for message in ('set', 'del', 'route'): dispatcher.connect( receiver=self.forward, sender=source, signal=(message, sf), ) else: print("""NULL ROUTE bound""", self)
def getTimer(self, context): """Retrieve the timer for this time-sensor""" timerObject = context.cache.getData(self, key='timer') if timerObject is None: timerObject = timer.Timer( duration=self.cycleInterval, repeating=self.loop, ) holder = context.cache.holder( self, key="timer", data=timerObject, ) for name in ("cycleInterval", "loop"): field = protofunctions.getField(self, name) holder.depend(self, field) timerObject.register(context) timerObject.start() timerObject.addEventHandler("fraction", function=self.onFraction) timerObject.addEventHandler("cycle", function=self.onCycle) return timerObject
def _forward(self, sender, signal, destination, destinationField, event=None, value=None, **arguments): """Do the low-level forwarding of the value to a target field""" if event is None: from vrml import event as eventmodule event = eventmodule.Event() signal, sourceField = signal if signal == 'del': value = sourceField.fget(sender) if destination and destinationField: destinationField = protofunctions.getField(destination, destinationField) if event and hasattr(event, "visited"): if event.visited((destination, destinationField), ): ### Short-circuit before a cycle is created... return event.visited((destination, destinationField), 1) if isinstance(destinationField, field.Field): try: value = destinationField.fset(destination, value, notify=0) except (ValueError, TypeError): traceback.print_exc() else: try: value = destinationField.__set__(destination, value) except (ValueError, TypeError): traceback.print_exc() dispatcher.send( signal=('route', destinationField), sender=destination, value=value, event=event, )
def getTimer( self, context ): """Retrieve the timer for this time-sensor""" timerObject = context.cache.getData( self, key='timer' ) if timerObject is None: timerObject = timer.Timer( duration = self.cycleInterval, repeating = self.loop, ) holder = context.cache.holder( self, key = "timer", data = timerObject, ) for name in ("cycleInterval", "loop"): field = protofunctions.getField( self, name ) holder.depend( self, field ) timerObject.register( context ) timerObject.start () timerObject.addEventHandler( "fraction", function = self.onFraction ) timerObject.addEventHandler( "cycle", function = self.onCycle ) return timerObject
def compile(self, mode=None): """Compile the box as a display-list""" if vbo.get_implementation(): vb = vbo.VBO(array(list(yieldVertices(self.size)), 'f')) def draw(textured=True, lit=True): vb.bind() try: glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS) try: glEnableClientState(GL_VERTEX_ARRAY) if lit: glEnableClientState(GL_NORMAL_ARRAY) glNormalPointer(GL_FLOAT, 32, vb + 8) if textured: glEnableClientState(GL_TEXTURE_COORD_ARRAY) glTexCoordPointer(2, GL_FLOAT, 32, vb) glVertexPointer(3, GL_FLOAT, 32, vb + 20) glDrawArrays(GL_TRIANGLES, 0, 36) finally: glPopClientAttrib() finally: vb.unbind() else: vb = array(list(yieldVertices(self.size)), 'f') def draw(textured=True, lit=True): glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS) try: glInterleavedArrays(GL_T2F_N3F_V3F, 0, vb) glDrawArrays(GL_TRIANGLES, 0, 36) finally: glPopClientAttrib() holder = mode.cache.holder(self, draw) holder.depend(self, protofunctions.getField(self, 'size')) return draw
def _forward( self, sender, signal, destination, destinationField, event=None, value=None, **arguments ): """Do the low-level forwarding of the value to a target field""" if event is None: from vrml import event as eventmodule event = eventmodule.Event() signal, sourceField = signal if signal == 'del': value = sourceField.fget( sender ) if destination and destinationField: destinationField = protofunctions.getField( destination, destinationField ) if event and hasattr(event, "visited"): if event.visited((destination, destinationField),): ### Short-circuit before a cycle is created... return event.visited( (destination,destinationField), 1) if isinstance( destinationField, field.Field ): try: value = destinationField.fset( destination, value, notify = 0 ) except (ValueError, TypeError): traceback.print_exc() else: try: value = destinationField.__set__( destination, value ) except (ValueError, TypeError): traceback.print_exc() dispatcher.send( signal = ('route',destinationField), sender = destination, value = value, event = event, )
def compile(self, mode=None): """Compile the IndexedLineSet into a display-list """ if self.coord and len(self.coord.point) and len(self.coordIndex): dl = displaylist.DisplayList() holder = mode.cache.holder(self, dl) for field in protofunctions.getFields(self): # change to any field requires a recompile holder.depend(self, field) for (n, attr) in [ (self.coord, 'point'), (self.color, 'color'), ]: if n: holder.depend(n, protofunctions.getField(n, attr)) points = self.coord.point indices = expandIndices(self.coordIndex) #XXX should do sanity checks here... if self.color and len(self.color.color): colors = self.color.color if self.colorPerVertex: if len(self.colorIndex): colorIndices = expandIndices(self.colorIndex) else: colorIndices = indices else: if len(self.colorIndex): # each item represents a single polyline colour colorIndices = self.colorIndex else: # each item in color used in turn by each polyline colorIndices = range(len(indices)) # compile the color-friendly ILS dl.start() try: glEnable(GL_COLOR_MATERIAL) for index in range(len(indices)): polyline = indices[index] color = colorIndices[index] try: color = int(color) except (TypeError, ValueError), err: glBegin(GL_LINE_STRIP) try: for i, c in map(None, polyline, color): if c is not None: # numpy treats None as retrieve all??? why? currentColor = colors[c] if currentColor is not None: glColor3d(*currentColor) glVertex3f(*points[i]) finally: glEnd() else: glColor3d(*colors[color]) glBegin(GL_LINE_STRIP) try: for i in polyline: glVertex3f(*points[i]) finally: glEnd() glDisable(GL_COLOR_MATERIAL) finally: dl.end()
def compile( self, mode=None ): """Compile the IndexedLineSet into a display-list """ if self.coord and len(self.coord.point) and len(self.coordIndex): dl = displaylist.DisplayList() holder = mode.cache.holder(self, dl) for field in protofunctions.getFields( self ): # change to any field requires a recompile holder.depend( self, field ) for (n, attr) in [ (self.coord, 'point'), (self.color, 'color'), ]: if n: holder.depend( n, protofunctions.getField(n,attr) ) points = self.coord.point indices = expandIndices( self.coordIndex ) #XXX should do sanity checks here... if self.color and len(self.color.color): colors = self.color.color if self.colorPerVertex: if len(self.colorIndex): colorIndices = expandIndices( self.colorIndex ) else: colorIndices = indices else: if len(self.colorIndex): # each item represents a single polyline colour colorIndices = self.colorIndex else: # each item in color used in turn by each polyline colorIndices = range(len(indices)) # compile the color-friendly ILS dl.start() try: glEnable( GL_COLOR_MATERIAL ) for index in range(len(indices)): polyline = indices[index] color = colorIndices[index] try: color = int(color) except (TypeError,ValueError), err: glBegin( GL_LINE_STRIP ) try: for i,c in map(None, polyline, color): if c is not None: # numpy treats None as retrieve all??? why? currentColor = colors[c] if currentColor is not None: glColor3d( *currentColor ) glVertex3f(*points[i]) finally: glEnd() else: glColor3d( *colors[color] ) glBegin( GL_LINE_STRIP ) try: for i in polyline: glVertex3f(*points[i]) finally: glEnd() glDisable( GL_COLOR_MATERIAL ) finally: dl.end()