| Line | Revision | Contents |
| 1 | 1 | """Vertex-array-based geometry node for faces, lines and points""" |
| 2 | from OpenGL.GL import * |
|
| 3 | from OpenGLContext.arrays import * |
|
| 4 | import polygonsort |
|
| 5 | from OpenGLContext import triangleutilities |
|
| 6 | from OpenGLContext.debug.logs import geometry_log |
|
| 7 | from OpenGL.arrays import vbo |
|
| 8 | ||
| 9 | try: |
|
| 10 | contiguous |
|
| 11 | except NameError: |
|
| 12 | def contiguous( source, typecode=None ): |
|
| 13 | """Force source to be a contiguous array""" |
|
| 14 | if isinstance( source, ArrayType): |
|
| 15 | if not hasattr(source, 'iscontiguous' ): |
|
| 16 | # XXX apparently numpy arrays are always contiguous??? |
|
| 17 | return source |
|
| 18 | if source.iscontiguous() and (typecode is None or typecode==typeCode(source)): |
|
| 19 | return source |
|
| 20 | else: |
|
| 21 | return array(source,typecode or typeCode(source)) |
|
| 22 | elif typecode: |
|
| 23 | return array( source, typecode ) |
|
| 24 | else: |
|
| 25 | return array( source ) |
|
| 26 | ||
| 27 | FORCE_CONTIGUOUS = 1 |
|
| 28 | ||
| 29 | ||
| 30 | class ArrayGeometry(object): |
|
| 31 | """Vertex-array-based geometry node for faces, lines and points |
|
| 32 | ||
| 33 | The ArrayGeometry class allows for rendering various |
|
| 34 | types of geometry using the vertex-array extensions of |
|
| 35 | OpenGL 1.1 and above. |
|
| 36 | |
|
| 37 | The ArrayGeometry is a non-node-object used by the |
|
| 38 | IndexedFaceSet for rendering an array of triangle |
|
| 39 | vertices. Originally it also handled the PointSet |
|
| 40 | and IndexedLineSet. The ArrayGeometry object is |
|
| 41 | cached using the cache module, and regenerated if |
|
| 42 | the holding object changes field values or is |
|
| 43 | deleted. |
|
| 44 | """ |
|
| 45 | def __init__ ( |
|
| 46 | self, |
|
| 47 | vertexArray,# array of vertex coordinates to draw |
|
| 48 | colorArray= None, # optional array of vertex colors |
|
| 49 | normalArray= None, # optional array of normals |
|
| 50 | textureCoordinateArray= None, # optional array of texture coordinates |
|
| 51 | objectType= GL_TRIANGLES, # type of primitive, see glDrawArrays, allowed are: |
|
| 52 | #GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, |
|
| 53 | #GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_QUAD_STRIP, |
|
| 54 | #GL_QUADS, and GL_POLYGON |
|
| 55 | startIndex = 0, # the index from which to draw, see glDrawArrays |
|
| 56 | count = -1, # by default, render the whole array (len(vertexArray)), see glDrawArrays |
|
| 57 | ccw = 1, # determines winding direction |
|
| 58 | solid = 1, # whether backspace culling may be enabled |
|
| 59 | ): |
|
| 60 | """Initialize the ArrayGeometry |
|
| 61 | ||
| 62 | vertexArray -- array of vertex coordinates to draw |
|
| 63 | colorArray = None -- optional array of vertex colors |
|
| 64 | normalArray = None -- optional array of normals |
|
| 65 | textureCoordinateArray = None -- optional array of |
|
| 66 | texture coordinates |
|
| 67 | objectType= GL_TRIANGLES -- type of primitive, see |
|
| 68 | glDrawArrays. Allowed values are: |
|
| 69 | GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, |
|
| 70 | GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, |
|
| 71 | GL_QUAD_STRIP, GL_QUADS, and GL_POLYGON |
|
| 72 | though few of those save points, lines and triangles |
|
| 73 | have actually been tested. Only triangles is currently |
|
| 74 | used. |
|
| 75 | startIndex = 0 -- the index from which to draw, |
|
| 76 | see glDrawArrays |
|
| 77 | count = -1 -- by default, render the whole array |
|
| 78 | (len(vertexArray)), see glDrawArrays |
|
| 79 | ccw = 1 -- determines winding direction |
|
| 80 | see glFrontFace |
|
| 81 | solid = 1 -- whether backspace culling should be enabled |
|
| 82 | see glEnable( GL_CULL_FACE ) |
|
| 83 | """ |
|
| 84 | geometry_log.debug( 'New array geometry node' ) |
|
| 85 | if FORCE_CONTIGUOUS: |
|
| 86 | if vertexArray is not None and len(vertexArray): |
|
| 87 | vertexArray = contiguous( vertexArray ) |
|
| 88 | if colorArray is not None and len(colorArray): |
|
| 89 | colorArray = contiguous( colorArray ) |
|
| 90 | if normalArray is not None and len(normalArray): |
|
| 91 | normalArray = contiguous( normalArray ) |
|
| 92 | if textureCoordinateArray is not None and len(textureCoordinateArray): |
|
| 93 | textureCoordinateArray = contiguous( textureCoordinateArray ) |
|
| 94 | if vbo.get_implementation(): |
|
| 95 | geometry_log.debug( "VBO implementation available" ) |
|
| 96 | if vertexArray is not None and len(vertexArray): |
|
| 97 | vertexArray = vbo.VBO( vertexArray ) |
|
| 98 | if colorArray is not None and len(colorArray): |
|
| 99 | colorArray = vbo.VBO( colorArray ) |
|
| 100 | if normalArray is not None and len(normalArray): |
|
| 101 | normalArray = vbo.VBO( normalArray ) |
|
| 102 | if textureCoordinateArray is not None and len(textureCoordinateArray): |
|
| 103 | textureCoordinateArray = vbo.VBO( textureCoordinateArray ) |
|
| 104 | if count < 0: |
|
| 105 | count = len (vertexArray) |
|
| 106 | self.vertices = vertexArray |
|
| 107 | self.colours = colorArray |
|
| 108 | self.normals = normalArray |
|
| 109 | self.textures = textureCoordinateArray |
|
| 110 | self.arguments = (objectType, startIndex,count) |
|
| 111 | geometry_log.debug( ' array geometry: %s, %s', self.arguments, len(self.vertices) ) |
|
| 112 | if ccw: |
|
| 113 | self.ccw = GL_CCW |
|
| 114 | else: |
|
| 115 | self.ccw = GL_CW |
|
| 116 | self.solid = solid |
|
| 117 | def callBound( self, function, array ): |
|
| 118 | if hasattr( array, 'bind' ): |
|
| 119 | array.bind() |
|
| 120 | try: |
|
| 121 | return function(array) |
|
| 122 | finally: |
|
| 123 | array.unbind() |
|
| 124 | else: |
|
| 125 | return function(array) |
|
| 126 | def render ( |
|
| 127 | self, |
|
| 128 | visible = 1, # can skip normals and textures if not |
|
| 129 | lit = 1, # can skip normals if not |
|
| 130 | textured = 1, # can skip textureCoordinates if not |
|
| 131 | transparent = 0, # need to sort triangle geometry... |
|
| 132 | mode = None, # the renderpass object for which we compile |
|
| 133 | ): |
|
| 134 | """Render the ArrayGeometry object |
|
| 135 | ||
| 136 | called by IndexedFaceSet.render to do the actual |
|
| 137 | rendering of the node. |
|
| 138 | """ |
|
| 139 | if not len(self.vertices): |
|
| 140 | return 1 # we are already finished |
|
| 141 | vboAvailable = bool(vbo.get_implementation()) |
|
| 142 | glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS) |
|
| 143 | glPushAttrib(GL_ALL_ATTRIB_BITS) |
|
| 144 | try: |
|
| 145 | glEnableClientState( GL_VERTEX_ARRAY ) |
|
| 146 | 63 | self.callBound( glVertexPointerf, self.vertices) |
| 147 | 1 | if visible and self.colours is not None: |
| 148 | # make the color field alter the diffuse color, should instead be aware of current material/lighting... |
|
| 149 | glColorMaterial( GL_FRONT_AND_BACK, GL_DIFFUSE) |
|
| 150 | glEnable( GL_COLOR_MATERIAL ) |
|
| 151 | glEnableClientState( GL_COLOR_ARRAY ) |
|
| 152 | 56 | self.callBound( glColorPointerf, self.colours) |
| 153 | 1 | # else: |
| 154 | # glDisableClientState( GL_COLOR_ARRAY ) |
|
| 155 | if lit and self.normals is not None: |
|
| 156 | glEnableClientState( GL_NORMAL_ARRAY ) |
|
| 157 | 56 | self.callBound( glNormalPointerf, self.normals) |
| 158 | 1 | glEnable(GL_NORMALIZE); # should do this explicitly eventually |
| 159 | else: |
|
| 160 | glDisable( GL_LIGHTING ) |
|
| 161 | # glDisableClientState( GL_NORMAL_ARRAY ) |
|
| 162 | |
|
| 163 | if visible and textured and self.textures is not None: |
|
| 164 | glEnableClientState( GL_TEXTURE_COORD_ARRAY ) |
|
| 165 | 56 | self.callBound( glTexCoordPointerf, self.textures ) |
| 166 | 1 | # else: |
| 167 | # glDisableClientState( GL_TEXTURE_COORD_ARRAY ) |
|
| 168 | glFrontFace( self.ccw) |
|
| 169 | if self.solid:# and not transparent: |
|
| 170 | glEnable( GL_CULL_FACE ) |
|
| 171 | else: |
|
| 172 | glDisable( GL_CULL_FACE ) |
|
| 173 | # do the actual rendering |
|
| 174 | if visible and transparent: |
|
| 175 | 123 | self.drawTransparent( mode = mode ) |
| 176 | 1 | else: |
| 177 | self.draw() |
|
| 178 | # cleanup the environment |
|
| 179 | finally: |
|
| 180 | glPopAttrib() |
|
| 181 | glPopClientAttrib() |
|
| 182 | return 1 |
|
| 183 | def draw( self ): |
|
| 184 | """Does the actual rendering after the arrays are set up |
|
| 185 | ||
| 186 | At the moment, is a simple call to glDrawArrays |
|
| 187 | """ |
|
| 188 | 21 | # geometry_log.debug( 'Drawing array geometry: %s, %s', self.arguments, len(self.vertices) ) |
| 189 | glDrawArrays( *self.arguments ) |
|
| 190 | # geometry_log.debug( 'Finished array geometry' ) |
|
| 191 | 123 | def drawTransparent( self, mode ): |
| 192 | 1 | """Same as draw, but called when a transparent render is required |
| 193 | ||
| 194 | This uses triangleutilities and polygonsort to render |
|
| 195 | the polygons in view-depth-sorted order (back to front). |
|
| 196 | ||
| 197 | It does not provide for automatically tesselating |
|
| 198 | intersecting transparent polygons, so there will |
|
| 199 | be potential rendering artifacts. |
|
| 200 | """ |
|
| 201 | if not hasattr( self, 'centers'): |
|
| 202 | self.centers = triangleutilities.centers( self.vertices ) |
|
| 203 | indices = polygonsort.indices( |
|
| 204 | polygonsort.distances( |
|
| 205 | 123 | self.centers, |
| 206 | modelView = mode.getModelView(), |
|
| 207 | projection = mode.getProjection(), |
|
| 208 | viewport = mode.getViewport(), |
|
| 209 | 1 | ) |
| 210 | 17 | ).astype( 'I' ) |
| 211 | 1 | objectType = self.arguments[0] |
| 212 | assert objectType == GL_TRIANGLES, """Only triangles are sortable, a non-triangle mesh was told to be transparent!""" |
|
| 213 | glDrawElementsui( |
|
| 214 | objectType, |
|
| 215 | indices |
|
| 216 | ) |
|
| 217 | |
Loggerhead 1.10 is a web-based interface for Bazaar branches