def draw_elements(self, mode, indices): """ Draw the attribute arrays using a specified set of vertices, in the specified mode. Only call when the program is enabled. Parameters ---------- mode : GL_ENUM GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN indices : numpy_array or ElementBuffer The indices to the vertices in the vertex arrays to draw. For performance, ElementBuffer objects are recommended over numpy arrays. If an ElementBuffer is provided, this method takes care of enabling it. """ # Check if not self._active: raise ProgramError('Program must be active for drawing.') # Upload any attributes and uniforms if necessary for variable in (self.attributes + self.uniforms): if variable.active: variable.upload(self) # Prepare and draw if isinstance(indices, ElementBuffer): # Activate self.activate_object(indices) # Prepare offset = None # todo: allow the use of offset gltype = ElementBuffer.DTYPE2GTYPE[indices.dtype.name] # Draw gl.glDrawElements(mode, indices.count, gltype, offset) elif isinstance(indices, np.ndarray): # Get type gltype = ElementBuffer.DTYPE2GTYPE.get(indices.dtype.name, None) if gltype is None: raise ValueError('Unsupported data type for ElementBuffer.') elif gltype == gl.GL_UNSIGNED_INT and not ext_available( 'element_index_uint'): raise ValueError( 'element_index_uint extension needed for uint32 ElementBuffer.' ) # Draw gl.glDrawElements(mode, indices.count, gltype, indices) else: raise ValueError( "draw_elements requires an ElementBuffer or a numpy array.")
def on_paint(self, event): gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) # Activate program and texture gl.glUseProgram(self._prog_handle) gl.glBindTexture(gl.GL_TEXTURE_2D, self._tex_handle) # Set attributes (again, the loc can be cached) loc = gl.glGetAttribLocation(self._prog_handle, 'a_position'.encode('utf-8')) gl.glEnableVertexAttribArray(loc) if use_buffers: gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._positions_handle) gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, 0, None) else: gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0) # 0 means do not use buffer gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, 0, positions) # loc = gl.glGetAttribLocation(self._prog_handle, 'a_texcoord'.encode('utf-8')) gl.glEnableVertexAttribArray(loc) if use_buffers: gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._texcoords_handle) gl.glVertexAttribPointer(loc, 2, gl.GL_FLOAT, False, 0, None) else: gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0) # 0 means do not use buffer gl.glVertexAttribPointer(loc, 2, gl.GL_FLOAT, False, 0, texcoords) # Set uniforms (note that you could cache the locations) loc = gl.glGetUniformLocation(self._prog_handle, 'u_view'.encode('utf-8')) gl.glUniformMatrix4fv(loc, 1, False, self.view) loc = gl.glGetUniformLocation(self._prog_handle, 'u_model'.encode('utf-8')) gl.glUniformMatrix4fv(loc, 1, False, self.model) loc = gl.glGetUniformLocation(self._prog_handle, 'u_projection'.encode('utf-8')) gl.glUniformMatrix4fv(loc, 1, False, self.projection) # Draw if use_buffers: gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._faces_handle) gl.glDrawElements(gl.GL_TRIANGLES, faces.size, gl.GL_UNSIGNED_INT, None) else: gl.glDrawElements(gl.GL_TRIANGLES, faces.size, gl.GL_UNSIGNED_INT, faces)
def draw_elements(self, mode, indices): """ Draw the attribute arrays using a specified set of vertices, in the specified mode. Only call when the program is enabled. Parameters ---------- mode : GL_ENUM GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN indices : numpy_array or ElementBuffer The indices to the vertices in the vertex arrays to draw. For performance, ElementBuffer objects are recommended over numpy arrays. If an ElementBuffer is provided, this method takes care of enabling it. """ # Check if not self._active: raise ProgramError('Program must be active for drawing.') # Upload any attributes and uniforms if necessary for variable in (self.attributes + self.uniforms): if variable.active: variable.upload(self) # Prepare and draw if isinstance(indices, ElementBuffer): # Activate self.activate_object(indices) # Prepare offset = None # todo: allow the use of offset gltype = ElementBuffer.DTYPE2GTYPE[indices.dtype.name] # Draw gl.glDrawElements(mode, indices.count, gltype, offset) elif isinstance(indices, np.ndarray): # Get type gltype = ElementBuffer.DTYPE2GTYPE.get(indices.dtype.name, None) if gltype is None: raise ValueError('Unsupported data type for ElementBuffer.') elif gltype == gl.GL_UNSIGNED_INT and not ext_available('element_index_uint'): raise ValueError('element_index_uint extension needed for uint32 ElementBuffer.') # Draw gl.glDrawElements(mode, indices.count, gltype, indices) else: raise ValueError("draw_elements requires an ElementBuffer or a numpy array.")
def draw(self, mode, subset=None): """ Draw the vertices in the specified mode. If the program is not active, it is activated to do the drawing and then deactivated. Parameters ---------- mode : str POINTS, LINES, LINE_STRIP, LINE_LOOP, TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN. Case insensitive. Alternatively, the real GL enum can also be given. subset : {ElementBuffer, tuple} The subset of vertices to draw. This can be an ElementBuffer that specifies the indices of the vertices to draw, or a tuple that specifies the slice: (start, end). The second element in this tuple can be None to specify the maximum length. If the subset is not given or None, all vertices are drawn. """ # Check if active. If not, call recursively, but activated if not self._active: if self._error_enter: # An error message has already been shown, we stop here # because if we would continue we would very likely # just spew messages for spin-off errors. return with self: return self.draw(mode, subset) # Check mode mode = convert_to_enum(mode) if mode not in [gl.GL_POINTS, gl.GL_LINES, gl.GL_LINE_STRIP, gl.GL_LINE_LOOP, gl.GL_TRIANGLES, gl.GL_TRIANGLE_STRIP, gl.GL_TRIANGLE_FAN]: raise ValueError('Given mode is invalid: %r.' % mode) # Allow subset None if subset is None: subset = (0, None) # Upload any attributes and uniforms if necessary for variable in (self.attributes + self.uniforms): if variable.active: variable.upload(self) if isinstance(subset, ElementBuffer): # Draw elements # Prepare pointer or offset if isinstance(subset, ClientElementBuffer): ptr = subset.data else: ptr = None # Note that this can also be a ctypes.pointer offset # Activate self.activate_object(subset) # Prepare gltype = ElementBuffer.DTYPE2GTYPE[subset.dtype.name] if gltype == gl.GL_UNSIGNED_INT and not ext_available('element_index_uint'): raise ValueError('element_index_uint extension needed for uint32 ElementBuffer.') # Draw gl.glDrawElements(mode, subset.count, gltype, ptr) elif isinstance(subset, tuple): # Draw arrays # Check tuple ok = [isinstance(i, (int, type(None))) for i in subset] if len(subset) != 2 or not all(ok): raise ValueError('Subset must be a two-element tuple with ' 'interegers or None.') # Get start, end, refcount start, end = subset start = start or 0 refcount = self._get_vertex_count() # Determine count if end is None: count = refcount if count is None: raise ProgramError("Could not determine element count for draw.") else: count = end - start if refcount and count > refcount: raise ValueError('Count is larger than known number of vertices.') # Draw gl.glDrawArrays(mode, start, count) else: raise ValueError('Given subset is of invalid type: %r.' % type(subset))