def draw(self): """Draw the object to the display buffer""" from pyglet import gl gl.glUseProgram(self._program) for kind in ('fill', 'line'): if self._counts[kind] > 0: if kind == 'line': if self._line_width <= 0.0: continue gl.glLineWidth(self._line_width) if self._line_loop: mode = gl.GL_LINE_LOOP else: mode = gl.GL_LINE_STRIP cmd = partial(gl.glDrawArrays, mode, 0, self._counts[kind]) else: gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._buffers[kind]['index']) cmd = partial(gl.glDrawElements, gl.GL_TRIANGLES, self._counts[kind], gl.GL_UNSIGNED_INT, 0) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._buffers[kind]['array']) loc_pos = gl.glGetAttribLocation(self._program, b'a_position') gl.glEnableVertexAttribArray(loc_pos) gl.glVertexAttribPointer(loc_pos, 2, gl.GL_FLOAT, gl.GL_FALSE, 0, 0) loc_col = gl.glGetUniformLocation(self._program, b'u_color') gl.glUniform4f(loc_col, *self._colors[kind]) cmd() # The following line is probably only necessary because # Pyglet makes some assumptions about the GL state that # it perhaps shouldn't. Without it, Text might not # render properly (see #252) gl.glDisableVertexAttribArray(loc_pos) gl.glUseProgram(0)
def render(shape: VertexBuffer): """ Render an shape previously created with a ``create`` function. """ # Set color if shape.color is None: raise ValueError("Error: Color parameter not set.") gl.glLoadIdentity() gl.glBindBuffer(gl.GL_ARRAY_BUFFER, shape.vbo_vertex_id) gl.glVertexPointer(2, gl.GL_FLOAT, 0, 0) if shape.line_width: gl.glLineWidth(shape.line_width) if len(shape.color) == 4: gl.glColor4ub(shape.color[0], shape.color[1], shape.color[2], shape.color[3]) gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) elif len(shape.color) == 3: gl.glDisable(gl.GL_BLEND) gl.glColor4ub(shape.color[0], shape.color[1], shape.color[2], 255) gl.glDrawArrays(shape.draw_mode, 0, shape.size)
def draw(self, uniforms, text, quad, textures=(), *args, **kwargs): glUseProgram(self) glDisable(GL_DEPTH_TEST) quad.enable() glUniform3f(self.uniforms[b'color'], 0.3, 0.3, 0.5) glUniformMatrix3fv( self.uniforms[b'transformation'], 1, GL_TRUE, text.get_transformation_matrix_2D().ctypes.data_as(POINTER(GLfloat)) ) textures.enable(slot=0) glUniform1i(self.uniforms[b'font_atlas'], 0) quad.draw() glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) glBindTexture(GL_TEXTURE_2D, 0) glDisableVertexAttribArray(0) glEnable(GL_DEPTH_TEST)
def draw(self, uniforms, entities, models, *args, **kwargs): glUseProgram(self) glUniformMatrix4fv( self.uniforms[b'perspective'], 1, GL_TRUE, uniforms.get(b'perspective').ctypes.data_as(POINTER(GLfloat)) ) glUniformMatrix4fv( self.uniforms[b'view'], 1, GL_TRUE, uniforms.get(b'view').ctypes.data_as(POINTER(GLfloat)) ) for model_index, entity_list in entities.items(): model = models[model_index] model.enable() for entity in entity_list: glUniformMatrix4fv( self.uniforms[b'transformation'], 1, GL_TRUE, entity.get_transformation_matrix().ctypes.data_as(POINTER(GLfloat)) ) glUniform3f(self.uniforms[b'color'], *entity.color) model.draw() glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) glBindTexture(GL_TEXTURE_2D, 0) glDisableVertexAttribArray(0)
def draw(self, uniforms, entities, models, textures=(), lights=(), *args, **kwargs): glUseProgram(self) # PREPARE SHADER glUniformMatrix4fv( # ctypes.data_as must be here and not at initialization. self.uniforms[b'perspective'], 1, GL_TRUE, uniforms.get(b'perspective').ctypes.data_as(POINTER(GLfloat)) ) glUniformMatrix4fv( self.uniforms[b'view'], 1, GL_TRUE, uniforms.get(b'view').ctypes.data_as(POINTER(GLfloat)) ) for i, entity in enumerate(lights): glUniform3f(self.uniforms[b'light[' + bytes(str(i), 'utf-8') + b'].position'], *entity.location) glUniform3f(self.uniforms[b'light[' + bytes(str(i), 'utf-8') + b'].color'], *entity.color) glUniform1f(self.uniforms[b'light[' + bytes(str(i), 'utf-8') + b'].constant'], entity.attenuation[0]) glUniform1f(self.uniforms[b'light[' + bytes(str(i), 'utf-8') + b'].linear'], entity.attenuation[1]) glUniform1f(self.uniforms[b'light[' + bytes(str(i), 'utf-8') + b'].quadratic'], entity.attenuation[1]) # PREPARE MODELS for model_index, texture_mapping in self.entities.items(): model = models[model_index] model.enable() # PREPARE TEXTURES glActiveTexture(GL_TEXTURE0) glActiveTexture(GL_TEXTURE0 + 1) for texture_list, entity_list in texture_mapping.items(): if hasattr(texture_list, '__iter__'): glBindTexture(GL_TEXTURE_2D, textures[0]) glUniform1i(self.uniforms[b'diffuse_texture'], 0) glBindTexture(GL_TEXTURE_2D, textures[1]) glUniform1i(self.uniforms[b'specular_texture'], 1) # textures[0].enable(slot=0) # textures[1].enable(slot=1) else: textures[texture_list].enable(slot=0) glUniform1i(self.uniforms[b'diffuse_texture'], 0) # PREPARE ENTITIES for entity in entity_list: glUniformMatrix4fv( self.uniforms[b'transformation'], 1, GL_TRUE, entity.get_transformation_matrix().ctypes.data_as(POINTER(GLfloat)) ) model.draw() glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) glBindTexture(GL_TEXTURE_2D, 0) glDisableVertexAttribArray(0) glDisableVertexAttribArray(1) glDisableVertexAttribArray(2)
def render_to_texture(): # select the target to draw into gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, framebuffer) draw_buffers = (gl.GLenum * 1)(gl.GL_COLOR_ATTACHMENT0) gl.glDrawBuffers(1, draw_buffers) gl.glViewport(0, 0, FB_WIDTH, FB_HEIGHT) # clear the destination gl.glClearColor(0.5, 0.6, 0.7, 1.0) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) # prepare the rendering gl.glUseProgram(render_program) # send the vertex data data = (COLOR_VERTEX * 3)(((-0.6, -0.5), (1.0, 0.0, 0.0, 1.0)), ((0.6, -0.5), (0.0, 1.0, 0.0, 1.0)), ((0.0, 0.5), (0.0, 0.0, 1.0, 1.0))) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, render_vertexbuffer) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(data), data, gl.GL_DYNAMIC_DRAW) # draw using the vertex array for vertex information gl.glBindVertexArray(render_vao) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3) gl.glBindVertexArray(0)
def copy_texture_to_screen(): # select the target to draw into gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0) gl.glViewport(0, 0, window.width, window.height) # clear the destination gl.glClearColor(0.4, 0.4, 0.4, 1.0) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) # select the program for drawing gl.glUseProgram(copy_program) # send the vertex data data = (TEXTURE_VERTEX * 8)(((-0.9, -0.9), (0.0, 0.0)), ((0.5, -0.9), (1.0, 0.0)), ((0.5, 0.5), (1.0, 1.0)), ((-0.9, 0.5), (0.0, 1.0)), ((0.6, 0.6), (0.0, 1.0)), ((1.0, 0.6), (1.0, 1.0)), ((1.0, 1.0), (1.0, 0.0)), ((0.6, 1.0), (0.0, 0.0)), ) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, copy_vertexbuffer) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(data), data, gl.GL_DYNAMIC_DRAW) # draw gl.glBindVertexArray(copy_vao) gl.glDrawArrays(gl.GL_QUADS, 0, 8) gl.glBindVertexArray(0)
def _draw_rects(shape_list, vertex_vbo_id, texture_coord_vbo_id): """ Draw a set of rectangles using vertex buffers. This is more efficient than drawing them individually. """ GL.glEnable(GL.GL_BLEND) GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA) GL.glEnable(GL.GL_TEXTURE_2D) GL.glHint(GL.GL_POLYGON_SMOOTH_HINT, GL.GL_NICEST) GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST) # GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) # GL.glMatrixMode(GL.GL_MODELVIEW) # GL.glDisable(GL.GL_BLEND) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vertex_vbo_id) GL.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY) GL.glEnableClientState(GL.GL_VERTEX_ARRAY) GL.glVertexPointer(2, GL.GL_FLOAT, 0, 0) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, texture_coord_vbo_id) offset = 0 for shape in shape_list: if shape.can_cache: texture_coord_vbo_id = None GL.glColor4f(1, 1, 1, shape.alpha) _render_rect_filled(shape, offset, shape.texture.texture_id, texture_coord_vbo_id) offset += 4 else: shape.draw()
def setup_copy_vertexbuffer(): ''' Create the vertexbuffer object for the copying program ''' # gl.glGenVertexArrays(1, ctypes.byref(copy_vao)) gl.glGenBuffers(1, ctypes.byref(copy_vertexbuffer)) loc_position = gl.glGetAttribLocation(copy_program, ctypes.create_string_buffer(b'position')) loc_texcoord = gl.glGetAttribLocation(copy_program, ctypes.create_string_buffer(b'texcoord')) if loc_position < 0: print('Warning: position is not used in the shader') if loc_texcoord < 0: print('Warning: texcoord is not used in the shader') gl.glBindVertexArray(copy_vao) gl.glEnableVertexAttribArray(loc_position) gl.glEnableVertexAttribArray(loc_texcoord) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, copy_vertexbuffer) gl.glVertexAttribPointer(loc_position, 2, gl.GL_FLOAT, False, ctypes.sizeof(TEXTURE_VERTEX), ctypes.c_void_p(TEXTURE_VERTEX.position.offset)) gl.glVertexAttribPointer(loc_texcoord, 2, gl.GL_FLOAT, False, ctypes.sizeof(TEXTURE_VERTEX), ctypes.c_void_p(TEXTURE_VERTEX.texcoord.offset)) gl.glBindVertexArray(0)
def create_with_size(cls, size: int, usage: str = 'static'): """Create an empty Buffer storage of the given size.""" empty_buffer = Buffer(b"", usage=usage) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, empty_buffer.buffer_id) gl.glBufferData(gl.GL_ARRAY_BUFFER, size, None, Buffer.usages[usage]) empty_buffer.size = size return empty_buffer
def draw(self, shader): attribute_table = shader.attribute_table self.indexed_vbo.bind() # Bind all attributes. location_list = [] # Used to disable all VertexAttribArrays. for name, vbo in self.vbo_array.items(): vbo.bind() attribute_location = attribute_table[name] location_list.append(attribute_location) glEnableVertexAttribArray(attribute_location) # specify that the data for the attribute will be pulled from the buffer that is currently bound to # GL_ARRAY_BUFFER. (http://stackoverflow.com/questions/30016833/multiple-in-attributes-in-shader-opengl) glVertexAttribPointer(attribute_location, vbo.dimension, vbo.data_type, GL_FALSE, 0, 0) # Draw. # glDrawArrays(GL_TRIANGLES, 0, vbo.count) glDrawElements(GL_TRIANGLES, self.indexed_vbo.count, self.indexed_vbo.data_type, 0) # Disable and unbind everything. for location in location_list: glDisableVertexAttribArray(location) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) glBindBuffer(GL_ARRAY_BUFFER, 0)
def __init__(self): self.fbo = gl.GLuint(0) self.rendered_texture = gl.GLuint(0) self.depthrenderbuffer = gl.GLuint(0) self.pickingbuffer = gl.GLuint(0) self.vertex_buffer = gl.GLuint(0) self.program = GlProgram(shaders.vertex_copy, shaders.fragment_copy) gl.glGenBuffers(1, pointer(self.vertex_buffer)) data = (gl.GLfloat * 16)(-1, -1, 0, 0, - 1, 1, 0, 1, 1, 1, 1, 1, 1, -1, 1, 0) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertex_buffer) gl.glBufferData(gl.GL_ARRAY_BUFFER, sizeof(data), data, gl.GL_STATIC_DRAW) gl.glGenFramebuffers(1, pointer(self.fbo)) if not self.fbo: logging.error('failed fbo') gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.fbo) gl.glGenTextures(1, pointer(self.rendered_texture)) if not self.rendered_texture: logging.error('failed rendered_texture') gl.glGenRenderbuffers(1, pointer(self.depthrenderbuffer)) gl.glGenRenderbuffers(1, pointer(self.pickingbuffer)) self.resize(1, 1)
def _enable_attrib(self, buf_desc: BufferDescription): buff = buf_desc.buffer stride = sum(attribsize for _, attribsize, _ in buf_desc.formats) if buf_desc.instanced: if self.num_vertices == -1: raise ShaderException( "The first vertex attribute cannot be a per instance attribute." ) else: self.num_vertices = max(self.num_vertices, buff.size // stride) # print(f"Number of vertices: {self.num_vertices}") gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buff.buffer_id) offset = 0 for (size, attribsize, gl_type_enum), attrib in zip(buf_desc.formats, buf_desc.attributes): loc = gl.glGetAttribLocation(self.program, attrib.encode('utf-8')) if loc == -1: raise ShaderException( f"Attribute {attrib} not found in shader program") normalized = gl.GL_TRUE if attrib in buf_desc.normalized else gl.GL_FALSE gl.glVertexAttribPointer(loc, size, gl_type_enum, normalized, stride, c_void_p(offset)) # print(f"{attrib} of size {size} with stride {stride} and offset {offset}") if buf_desc.instanced: gl.glVertexAttribDivisor(loc, 1) offset += attribsize gl.glEnableVertexAttribArray(loc)
def set_vertex_attrib(self, name, data): """This is an ugly way to set vertex attribute data in a shader, it lacks the flexibility of setting several attributes in one vertex buffer. name: the attribute name in the shader. data: a list of vertex attributes (positions, colors, texcoords, normals,...) example: name = 'positions', data = [(1, 1, 0), (2, 2, 1), ...] the items in data must all be 1D lists(or tuples) of the same length. """ data_flatten = [x for vertex in data for x in vertex] size = len(data[0]) data_ctype = (gl.GLfloat * len(data_flatten))(*data_flatten) vbo_id = gl.GLuint(0) gl.glGenBuffers(1, ct.byref(vbo_id)) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo_id) gl.glBufferData(gl.GL_ARRAY_BUFFER, ct.sizeof(data_ctype), data_ctype, gl.GL_STATIC_DRAW) location = gl.glGetAttribLocation(self.program, name.encode('ascii')) gl.glEnableVertexAttribArray(location) gl.glVertexAttribPointer(location, size, gl.GL_FLOAT, gl.GL_FALSE, 0, 0) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0) return vbo_id
def on_draw(self): """ Render the screen. """ start = time.time() GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) GL.glMatrixMode(GL.GL_MODELVIEW) GL.glDisable(GL.GL_BLEND) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vertex_vbo_id) GL.glEnableClientState(GL.GL_VERTEX_ARRAY) GL.glVertexPointer(2, GL.GL_FLOAT, 0, 0) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.color_vbo_id) GL.glEnableClientState(GL.GL_COLOR_ARRAY) GL.glColorPointer(3, GL.GL_FLOAT, 0, 0) offset = 0 for shape in self.shape_list: render_rect_filled(shape, offset) offset += 4 elapsed = time.time() - start print(elapsed)
def read(self, size=-1, offset=0) -> bytes: """Read data from the buffer. :param int size: The bytes to read. -1 means the entire buffer (default) :param int offset: Byte read offset :rtype: bytes """ if size == -1: size = self._size # Catch this before confusing INVALID_OPERATION is raised if size < 1: raise ValueError("Attempting to read 0 or less bytes from buffer") # Manually detect this so it doesn't raise a confusing INVALID_VALUE error if size + offset > self._size: raise ValueError( ( "Attempting to read outside the buffer. " f"Buffer size: {self._size} " f"Reading from {offset} to {size + offset}" ) ) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._glo) ptr = gl.glMapBufferRange(gl.GL_ARRAY_BUFFER, offset, size, gl.GL_MAP_READ_BIT) data = string_at(ptr, size=size) gl.glUnmapBuffer(gl.GL_ARRAY_BUFFER) return data
def set_vertex_attrib(self, name, data): ''' this is an ugly way to set vertex attribute data in a shader. lacks the flexibility of setting several attributes in one vertex buffer. name: the attribute name in the shader. data: a list of vertex attributes (positions, colors, texcoords, normals,...) example: name = 'positions' data = [(1, 1, 0), (2, 2, 1), ...] the items in data must all be 1D lists(or tuples) of the same length. ''' data_flatten = [x for vertex in data for x in vertex] size = len(data[0]) data_ctype = (gl.GLfloat * len(data_flatten))(*data_flatten) vbo_id = gl.GLuint(0) gl.glGenBuffers(1, ct.byref(vbo_id)) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo_id) gl.glBufferData(gl.GL_ARRAY_BUFFER, ct.sizeof(data_ctype), data_ctype, gl.GL_STATIC_DRAW) location = gl.glGetAttribLocation(self.program, name.encode('ascii')) gl.glEnableVertexAttribArray(location) gl.glVertexAttribPointer(location, size, gl.GL_FLOAT, gl.GL_FALSE, 0, 0) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0) return vbo_id
def setup_render_vertexbuffer(): ''' Create the vertexbuffer object for the rendering program ''' gl.glGenVertexArrays(1, ctypes.byref(render_vao)) gl.glGenBuffers(1, ctypes.byref(render_vertexbuffer)) loc_position = gl.glGetAttribLocation(render_program, ctypes.create_string_buffer(b'position')) loc_color = gl.glGetAttribLocation(render_program, ctypes.create_string_buffer(b'color')) if loc_position < 0: print('Warning: position is not used in the shader') if loc_color < 0: print('Warning: color is not used in the shader') gl.glBindVertexArray(render_vao) gl.glEnableVertexAttribArray(loc_position) gl.glEnableVertexAttribArray(loc_color) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, render_vertexbuffer) gl.glVertexAttribPointer(loc_position, 2, gl.GL_FLOAT, False, ctypes.sizeof(COLOR_VERTEX), ctypes.c_void_p(COLOR_VERTEX.position.offset)) gl.glVertexAttribPointer(loc_color, 4, gl.GL_FLOAT, False, ctypes.sizeof(COLOR_VERTEX), ctypes.c_void_p(COLOR_VERTEX.color.offset)) gl.glBindVertexArray(0)
def send_data(self, data): data = (self.VERTEX * len(data))(*data) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertex_buffer_name) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(data), data, gl.GL_DYNAMIC_DRAW) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
def __init__(self, data, dimension=3): """ Vertex Buffer Object for storing data in OpenGl. Args: data: An array of values. dimension: Whether the array is 1D, 2D, 3D or 4D. """ data_type = c_float elements = len(data) buffer_type = data_type * elements buffer = buffer_type() buffer[:] = data # About 2.5 times faster than passing arguments during initialization. handle = c_uint() glGenBuffers(1, handle) glBindBuffer(GL_ARRAY_BUFFER, handle) glBufferData(GL_ARRAY_BUFFER, elements * sizeof(data_type), buffer, GL_STATIC_DRAW) glBindBuffer(GL_ARRAY_BUFFER, 0) super(VBO, self).__init__(handle.value) self.data_type = GL_FLOAT self.count = elements // dimension self.dimension = dimension
def __init__(self, **args): super(Window, self).__init__(**args) self.vao = gl.GLuint(0) gl.glGenVertexArrays(1, ctypes.byref(self.vao)) gl.glBindVertexArray(self.vao) self.vbo = gl.GLuint(0) gl.glGenBuffers(1, ctypes.byref(self.vbo)) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vbo) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(gl.GLfloat * len(vertex_positions)), (gl.GLfloat * len(vertex_positions))(*vertex_positions), gl.GL_STATIC_DRAW) gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE, 0, 0) gl.glEnableVertexAttribArray(0) self.ibo = gl.GLuint(0) gl.glGenBuffers(1, self.ibo) gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.ibo) gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, ctypes.sizeof(gl.GLuint * len(indices)), (gl.GLuint * len(indices))(*indices), gl.GL_STATIC_DRAW)
def data(self, buffer_type, data, offset): if buffer_type != "texture": gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.buffers[buffer_type]) if buffer_type == "color": offset *= 16 else: offset *= 12 gl_data = to_gl_float(data) length = len(data) * 4 gl.glBufferSubData(gl.GL_ARRAY_BUFFER, offset, length, gl_data) if buffer_type == "vertex": self.vertex_count += int(len(data) / 3) else: self.buffers["texture"] = gl.GLuint(0) gl.glGenTextures(1, self.buffers["texture"]) gl.glBindTexture(data.target, data.id) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST) gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, texture.width, texture.height, 0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, texture_data)
def copy_from_buffer(self, source: "Buffer", size=-1, offset=0, source_offset=0): """Copy data into this buffer from another buffer :param Buffer source: The buffer to copy from :param int size: The amount of bytes to copy :param int offset: The byte offset to write the data in this buffer :param int source_offset: The byte offset to read from the source buffer """ # Read the entire source buffer into this buffer if size == -1: size = source.size # TODO: Check buffer bounds if size + source_offset > source.size: raise ValueError("Attempting to read outside the source buffer") if size + offset > self._size: raise ValueError("Attempting to write outside the buffer") gl.glBindBuffer(gl.GL_COPY_READ_BUFFER, source.glo) gl.glBindBuffer(gl.GL_COPY_WRITE_BUFFER, self._glo) gl.glCopyBufferSubData( gl.GL_COPY_READ_BUFFER, gl.GL_COPY_WRITE_BUFFER, gl.GLintptr(source_offset), # readOffset gl.GLintptr(offset), # writeOffset size, # size (number of bytes to copy) )
def setup_render_vertexbuffer(): ''' Create the vertexbuffer object for the rendering program ''' gl.glGenVertexArrays(1, ctypes.byref(render_vao)) gl.glGenBuffers(1, ctypes.byref(render_vertexbuffer)) loc_position = gl.glGetAttribLocation( render_program, ctypes.create_string_buffer(b'position')) loc_color = gl.glGetAttribLocation(render_program, ctypes.create_string_buffer(b'color')) if loc_position < 0: print('Warning: position is not used in the shader') if loc_color < 0: print('Warning: color is not used in the shader') gl.glBindVertexArray(render_vao) gl.glEnableVertexAttribArray(loc_position) gl.glEnableVertexAttribArray(loc_color) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, render_vertexbuffer) gl.glVertexAttribPointer(loc_position, 2, gl.GL_FLOAT, False, ctypes.sizeof(COLOR_VERTEX), ctypes.c_void_p(COLOR_VERTEX.position.offset)) gl.glVertexAttribPointer(loc_color, 4, gl.GL_FLOAT, False, ctypes.sizeof(COLOR_VERTEX), ctypes.c_void_p(COLOR_VERTEX.color.offset)) gl.glBindVertexArray(0)
def vertex_attrib(self, name, data, size=2, stride=0, offset=0): """ Set vertex attribute data in a shader, lacks the flexibility of setting several attributes in one vertex buffer. Parameters ---------- name: the attribute name in the shader. data: a list of vertex attributes (positions, colors, ...) Example: name = "positions", data = [0, 0, 0, 1, 1, 0, 1, 1]. """ data_ctype = (gl.GLfloat * len(data))(*data) vbo_id = gl.GLuint(0) gl.glGenBuffers(1, ct.byref(vbo_id)) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo_id) gl.glBufferData(gl.GL_ARRAY_BUFFER, ct.sizeof(data_ctype), data_ctype, gl.GL_STATIC_DRAW) location = gl.glGetAttribLocation(self.program, name.encode("ascii")) gl.glEnableVertexAttribArray(location) gl.glVertexAttribPointer(location, size, gl.GL_FLOAT, gl.GL_FALSE, stride, ct.c_void_p(offset)) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0) return vbo_id
def on_draw(self): """ Render the screen. """ start = time.time() float_size = ctypes.sizeof(ctypes.c_float) record_len = 10 * float_size GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) GL.glMatrixMode(GL.GL_MODELVIEW) GL.glEnableClientState(GL.GL_VERTEX_ARRAY) GL.glColor4ub(255, 0, 0, 255) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.rect_vbo.vbo_id) GL.glVertexPointer(2, GL.GL_FLOAT, record_len, 0) for i in range(len(self.shape_list)): shape = self.shape_list[i] GL.glLoadIdentity() GL.glTranslatef(shape.x, shape.y, 0) GL.glDrawArrays(GL.GL_QUADS, i * 8, 8) # GL.glDrawArrays(GL.GL_QUADS, # 0, # self.rect_vbo.size) elapsed = time.time() - start print(elapsed)
def setup_copy_vertexbuffer(): ''' Create the vertexbuffer object for the copying program ''' # gl.glGenVertexArrays(1, ctypes.byref(copy_vao)) gl.glGenBuffers(1, ctypes.byref(copy_vertexbuffer)) loc_position = gl.glGetAttribLocation( copy_program, ctypes.create_string_buffer(b'position')) loc_texcoord = gl.glGetAttribLocation( copy_program, ctypes.create_string_buffer(b'texcoord')) if loc_position < 0: print('Warning: position is not used in the shader') if loc_texcoord < 0: print('Warning: texcoord is not used in the shader') gl.glBindVertexArray(copy_vao) gl.glEnableVertexAttribArray(loc_position) gl.glEnableVertexAttribArray(loc_texcoord) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, copy_vertexbuffer) gl.glVertexAttribPointer(loc_position, 2, gl.GL_FLOAT, False, ctypes.sizeof(TEXTURE_VERTEX), ctypes.c_void_p(TEXTURE_VERTEX.position.offset)) gl.glVertexAttribPointer(loc_texcoord, 2, gl.GL_FLOAT, False, ctypes.sizeof(TEXTURE_VERTEX), ctypes.c_void_p(TEXTURE_VERTEX.texcoord.offset)) gl.glBindVertexArray(0)
def __init__( self, ctx, data: Optional[Any] = None, reserve: int = 0, usage: str = "static" ): """ :param Context ctx: The context this buffer belongs to :param Any data: The data this buffer should contain. It can be bytes or any object supporting the buffer protocol. :param int reserve: Create a buffer of a specific byte size :param str usage: A hit of this buffer is ``static`` or ``dynamic`` (can mostly be ignored) """ self._ctx = ctx self._glo = glo = gl.GLuint() self._size = -1 self._usage = Buffer._usages[usage] gl.glGenBuffers(1, byref(self._glo)) # print(f"glGenBuffers() -> {self._glo.value}") if self._glo.value == 0: raise RuntimeError("Cannot create Buffer object.") # print(f"glBindBuffer({self._glo.value})") gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._glo) # print(f"glBufferData(gl.GL_ARRAY_BUFFER, {self._size}, data, {self._usage})") if data is not None and len(data) > 0: self._size, data = data_to_ctypes(data) gl.glBufferData(gl.GL_ARRAY_BUFFER, self._size, data, self._usage) elif reserve > 0: self._size = reserve gl.glBufferData(gl.GL_ARRAY_BUFFER, self._size, None, self._usage) else: raise ValueError("Buffer takes byte data or number of reserved bytes") self.ctx.stats.incr("buffer") weakref.finalize(self, Buffer.release, self.ctx, glo)
def copy_texture_to_screen(): # select the target to draw into gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0) gl.glViewport(0, 0, window.width, window.height) # clear the destination gl.glClearColor(0.4, 0.4, 0.4, 1.0) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) # select the program for drawing gl.glUseProgram(copy_program) # send the vertex data data = (TEXTURE_VERTEX * 8)( ((-0.9, -0.9), (0.0, 0.0)), ((0.5, -0.9), (1.0, 0.0)), ((0.5, 0.5), (1.0, 1.0)), ((-0.9, 0.5), (0.0, 1.0)), ((0.6, 0.6), (0.0, 1.0)), ((1.0, 0.6), (1.0, 1.0)), ((1.0, 1.0), (1.0, 0.0)), ((0.6, 1.0), (0.0, 0.0)), ) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, copy_vertexbuffer) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(data), data, gl.GL_DYNAMIC_DRAW) # draw gl.glBindVertexArray(copy_vao) gl.glDrawArrays(gl.GL_QUADS, 0, 8) gl.glBindVertexArray(0)
def create_line_generic(draw_type: int, point_list: PointList, color: Color, line_width: float=1): """ This function is used by ``create_line_strip`` and ``create_line_loop``, just changing the OpenGL type for the line drawing. """ data = [] for point in point_list: data.append(point[0]) data.append(point[1]) vbo_id = gl.GLuint() gl.glGenBuffers(1, ctypes.pointer(vbo_id)) # Create a buffer with the data # This line of code is a bit strange. # (gl.GLfloat * len(data)) creates an array of GLfloats, one for each number # (*data) initalizes the list with the floats. *data turns the list into a # tuple. data2 = (gl.GLfloat * len(data))(*data) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo_id) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, gl.GL_STATIC_DRAW) shape = VertexBuffer(vbo_id, len(data) // 2, draw_type) shape.color = color shape.line_width = line_width return shape
def draw(self): ''' Draw the windows. ''' self.program.use() data = list(self.root.get_data(0, 0)) data = (gl.GLfloat * len(data))(*data) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.buffer) gl.glBufferData(gl.GL_ARRAY_BUFFER, sizeof(data), data, gl.GL_DYNAMIC_DRAW) gl.glActiveTexture(gl.GL_TEXTURE0) gl.glBindTexture(gl.GL_TEXTURE_2D, self.texture) if self.textmanager.dirty: # only upload the texture to the GPU if it has actually changed gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, # level gl.GL_R8, self.textmanager.width, self.textmanager.height, 0, gl.GL_RED, gl.GL_UNSIGNED_BYTE, ctypes.create_string_buffer(self.textmanager.img.tobytes())) self.textmanager.dirty = False self.program.uniform1i(b"tex", 0) # set to 0 because the texture is bound to GL_TEXTURE0 self.program.vertex_attrib_pointer(self.buffer, b"position", 4) # self.program.vertex_attrib_pointer(self.buffer, b"texcoord", 2, stride=4 * sizeof(gl.GLfloat), offset=2 * sizeof(gl.GLfloat)) gl.glDrawArrays(gl.GL_QUADS, 0, len(data) // 4)
def _set_points(self, points, kind, tris): """Helper to set fill and line points""" from pyglet import gl if points is None: self._counts[kind] = 0 points = np.asarray(points, dtype=np.float32, order='C') assert points.ndim == 2 and points.shape[1] == 2 array_count = points.size // 2 if kind == 'line' else points.size if kind == 'fill': assert tris is not None tris = np.asarray(tris, dtype=np.uint32, order='C') assert tris.ndim == 1 and tris.size % 3 == 0 tris.shape = (-1, 3) assert (tris < len(points)).all() self._tris[kind] = tris del tris self._points[kind] = points del points gl.glUseProgram(self._program) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._buffers[kind]['array']) gl.glBufferData(gl.GL_ARRAY_BUFFER, self._points[kind].size * 4, self._points[kind].tostring(), gl.GL_STATIC_DRAW) if kind == 'line': self._counts[kind] = array_count if kind == 'fill': self._counts[kind] = self._tris[kind].size gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._buffers[kind]['index']) gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, self._tris[kind].size * 4, self._tris[kind].tostring(), gl.GL_STATIC_DRAW) gl.glUseProgram(0)
def create_ellipse(width, height, color): """ This creates an ellipse vertex buffer object (VBO). It can later be drawn with ``render_ellipse_filled``. This method of drawing an ellipse is much faster than calling ``draw_ellipse_filled`` each frame. """ num_segments = 64 data = [] for i in range(num_segments + 1): theta = 2.0 * 3.1415926 * i / num_segments x = width * math.cos(theta) y = height * math.sin(theta) data.extend([x, y]) vbo_id = GL.GLuint() GL.glGenBuffers(1, ctypes.pointer(vbo_id)) v2f = data data2 = (GL.GLfloat*len(v2f))(*v2f) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id) GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW) shape = VertexBuffer(vbo_id, len(v2f)//2, width, height, color) return shape
def upload_indices(asset: ModelAsset, gl_usage=GL_STATIC_DRAW): for buffer in asset.index_buffers: # noinspection PyCallingNonCallable,PyTypeChecker index_data_gl = (GLint * len(buffer.indices))(*buffer.indices) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.id) index_buffer_size = sizeof(index_data_gl) glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_buffer_size, index_data_gl, gl_usage)
def __init__(self, type, data): self.type = type self.data = data self.id = gl.GLuint() gl.glGenBuffers(1, ctypes.pointer(self.id)) self.data_ptr = (gl.GLfloat * len(data))(*data) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.id) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(self.data_ptr), self.data_ptr, gl.GL_STATIC_DRAW)
def _read(self, size): """ Debug method to read data from the buffer. """ gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.buffer_id) ptr = gl.glMapBufferRange(gl.GL_ARRAY_BUFFER, gl.GLintptr(0), size, gl.GL_MAP_READ_BIT) print(f"Reading back from buffer:\n{string_at(ptr, size=size)}") gl.glUnmapBuffer(gl.GL_ARRAY_BUFFER)
def createVertexbuffer(vertexData, vertexSize=3, bufferType=GL.GL_VERTEX_ARRAY): """Create a static, single-storage Vertex Buffer Object (VBO). Parameters ---------- vertexData : :obj:`list` or :obj:`tuple` of :obj:`float` Coordinates as a 1D array of floats (e.g. [X0, Y0, Z0, X1, Y1, Z1, ...]) vertexSize : :obj:`int` Number of coordinates per-vertex, default is 3. bufferType : :obj:`int` The type of data stored in the buffer (e.g. GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY, GL_NORMAL_ARRAY, etc.) Returns ------- Vertexbuffer A descriptor with vertex buffer information. Examples -------- # vertices of a triangle verts = [ 1.0, 1.0, 0.0, # v0 0.0, -1.0, 0.0, # v1 -1.0, 1.0, 0.0] # v2 # load vertices to graphics device, return a descriptor vboDesc = createVertexbuffer(verts, 3) # draw GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vboDesc.id) GL.glVertexPointer(vboDesc.vertexSize, vboDesc.dtype, 0, None) GL.glEnableClientState(vboDesc.bufferType) GL.glDrawArrays(GL.GL_TRIANGLES, 0, vboDesc.indices) GL.glFlush() """ # convert values to ctypes float array count = len(vertexData) c_array = (GL.GLfloat * count)(*vertexData) # create a vertex buffer ID vboId = GL.GLuint() GL.glGenBuffers(1, ctypes.byref(vboId)) # new vertex descriptor vboDesc = Vertexbuffer(vboId, vertexSize, count, int(count / vertexSize), GL.GL_STATIC_DRAW, bufferType, GL.GL_FLOAT) # always float # bind and upload GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vboId) GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(c_array), c_array, GL.GL_STATIC_DRAW) # GL.glBindBuffer(GL.GL_ARRAY_BUFFER, 0) return vboDesc
def _create_device_objects(self): # save state last_texture = gl.GLint() gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D, byref(last_texture)) last_array_buffer = gl.GLint() gl.glGetIntegerv(gl.GL_ARRAY_BUFFER_BINDING, byref(last_array_buffer)) last_vertex_array = gl.GLint() gl.glGetIntegerv(gl.GL_VERTEX_ARRAY_BINDING, byref(last_vertex_array)) self._shader_handle = gl.glCreateProgram() # note: no need to store shader parts handles after linking vertex_shader = gl.glCreateShader(gl.GL_VERTEX_SHADER) fragment_shader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER) gl.glShaderSource(vertex_shader, 1, make_string_buffer(self.VERTEX_SHADER_SRC), None) gl.glShaderSource(fragment_shader, 1, make_string_buffer(self.FRAGMENT_SHADER_SRC), None) gl.glCompileShader(vertex_shader) gl.glCompileShader(fragment_shader) gl.glAttachShader(self._shader_handle, vertex_shader) gl.glAttachShader(self._shader_handle, fragment_shader) gl.glLinkProgram(self._shader_handle) # note: after linking shaders can be removed gl.glDeleteShader(vertex_shader) gl.glDeleteShader(fragment_shader) self._attrib_location_tex = gl.glGetUniformLocation(self._shader_handle, create_string_buffer(b"Texture")) self._attrib_proj_mtx = gl.glGetUniformLocation(self._shader_handle, create_string_buffer(b"ProjMtx")) self._attrib_location_position = gl.glGetAttribLocation(self._shader_handle, create_string_buffer(b"Position")) self._attrib_location_uv = gl.glGetAttribLocation(self._shader_handle, create_string_buffer(b"UV")) self._attrib_location_color = gl.glGetAttribLocation(self._shader_handle, create_string_buffer(b"Color")) self._vbo_handle = gl.GLuint() gl.glGenBuffers(1, byref(self._vbo_handle)) self._elements_handle = gl.GLuint() gl.glGenBuffers(1, byref(self._elements_handle)) self._vao_handle = gl.GLuint() gl.glGenVertexArrays(1, byref(self._vao_handle)) gl.glBindVertexArray(self._vao_handle) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._vbo_handle) gl.glEnableVertexAttribArray(self._attrib_location_position) gl.glEnableVertexAttribArray(self._attrib_location_uv) gl.glEnableVertexAttribArray(self._attrib_location_color) gl.glVertexAttribPointer(self._attrib_location_position, 2, gl.GL_FLOAT, gl.GL_FALSE, imgui.VERTEX_SIZE, c_void_p(imgui.VERTEX_BUFFER_POS_OFFSET)) gl.glVertexAttribPointer(self._attrib_location_uv, 2, gl.GL_FLOAT, gl.GL_FALSE, imgui.VERTEX_SIZE, c_void_p(imgui.VERTEX_BUFFER_UV_OFFSET)) gl.glVertexAttribPointer(self._attrib_location_color, 4, gl.GL_UNSIGNED_BYTE, gl.GL_TRUE, imgui.VERTEX_SIZE, c_void_p(imgui.VERTEX_BUFFER_COL_OFFSET)) # restore state gl.glBindTexture(gl.GL_TEXTURE_2D, cast((c_int*1)(last_texture), POINTER(c_uint)).contents) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, cast((c_int*1)(last_array_buffer), POINTER(c_uint)).contents) gl.glBindVertexArray(cast((c_int*1)(last_vertex_array), POINTER(c_uint)).contents)
def _set_vbo(vbo_id, points): """ Given a vertex buffer id, this sets the vertexes to be part of that buffer. """ data2 = (GL.GLfloat * len(points))(*points) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id) GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW)
def stripped_render(shape: VertexBuffer): """ Render an shape previously created with a ``create`` function. Used by ``ShapeElementList.draw()`` for drawing several shapes in a batch. """ gl.glBindBuffer(gl.GL_ARRAY_BUFFER, shape.vbo_vertex_id) gl.glVertexPointer(2, gl.GL_FLOAT, 0, 0) gl.glDrawArrays(shape.draw_mode, 0, shape.size)
def vertex_attrib_pointer(self, buffer, name, size, type=gl.GL_FLOAT, normalized=False, stride=0, offset=0): self.use() loc = gl.glGetAttribLocation(self.handle, ctypes.create_string_buffer(name)) if loc < 0: logging.warning('Attribute {} is not in the shader.'.format(name)) return gl.glEnableVertexAttribArray(loc) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer) gl.glVertexAttribPointer(loc, size, type, normalized, stride, ctypes.c_void_p(offset))
def write(self, data: Any, offset: int = 0): """Write byte data to the buffer. :param bytes data: The byte data to write. This can be bytes or any object supporting the buffer protocol. :param int offset: The byte offset """ gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._glo) size, data = data_to_ctypes(data) gl.glBufferSubData(gl.GL_ARRAY_BUFFER, gl.GLintptr(offset), size, data)
def __set_attributes(self): if self.__vao is None: self.__vao = util.vertex_array() gl.glBindVertexArray(self.__vao.value) # coord coord_loc = gl.glGetAttribLocation(self.__prog.value, "coord") gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.__geom_buffer.value) gl.glVertexAttribPointer(coord_loc, 3, gl.GL_FLOAT, gl.GL_FALSE, 0, 0) gl.glEnableVertexAttribArray(coord_loc)
def _set_vbo(vbo_id: gl.GLuint, points: List[float]): """ Given a vertex buffer id, this sets the vertexes to be part of that buffer. """ # todo what does it do? data2 = (gl.GLfloat*len(points))(*points) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo_id) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, gl.GL_STATIC_DRAW)
def __alloc(cls, target, format, usage): buf = super().__new__(cls) buf.owned = True buf.bid = GLuint() glGenBuffers(1, byref(buf.bid)) glBindBuffer(target, buf.bid) buf._usage = usage buf.format = BufferFormat.new(format) buf.target = target buf.mapinfo = None return buf
def create_vbo_for_rects(v2f): vbo_id = GL.GLuint() GL.glGenBuffers(1, ctypes.pointer(vbo_id)) data2 = (GL.GLfloat*len(v2f))(*v2f) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id) GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW) shape = VertexBuffer(vbo_id, len(v2f)//2) return shape
def render_rect_filled(shape, x, y): """ Render the shape at the right spot. """ # Set color GL.glDisable(GL.GL_BLEND) GL.glColor4ub(shape.color[0], shape.color[1], shape.color[2], 255) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, shape.vbo_id) GL.glVertexPointer(2, GL.GL_FLOAT, 0, 0) GL.glLoadIdentity() GL.glTranslatef(x + shape.width / 2, y + shape.height / 2, 0) GL.glDrawArrays(GL.GL_QUADS, 0, shape.size)
def bind(self, target=None): """ Bind the buffer to its target Arguments: target: Default to None. One of the GL target (such as GL_ARRAY_BUFFER) If None, use the default buffer target. """ if self.target is None: raise ValueError("Buffer target was not defined") target = target if target is not None else self.target glBindBuffer(target, self.bid)
def create_rect(width, height, color): """ Create a vertex buffer for a rectangle. """ v2f = [-width / 2, -height / 2, width / 2, -height / 2, width / 2, height / 2, -width / 2, height / 2] vbo_id = GL.GLuint() GL.glGenBuffers(1, ctypes.pointer(vbo_id)) data2 = (GL.GLfloat*len(v2f))(*v2f) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id) GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW) shape = VertexBuffer(vbo_id, len(v2f)//2, width, height, color) return shape
def create_colors(rect_list): """ Create a vertex buffer for a set of rectangles. """ v2f = [] for shape in rect_list: for i in range(4): v2f.extend(shape.color) vbo_id = GL.GLuint() GL.glGenBuffers(1, ctypes.pointer(vbo_id)) data2 = (GL.GLfloat*len(v2f))(*v2f) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id) GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW) return vbo_id
def __setup_data_buffer(self): data_ptr = ct.cast( np.ctypeslib.as_ctypes(self.__data), ct.POINTER(ct.c_float) ) self.__data_buffer = util.buffer() gl.glBindBuffer(gl.GL_TEXTURE_BUFFER, self.__data_buffer.value) gl.glBufferData(gl.GL_TEXTURE_BUFFER, ct.sizeof(ct.c_float)*self.__data.size, data_ptr, gl.GL_STATIC_DRAW) if self.__data_texture is None: self.__data_texture = util.texture() gl.glActiveTexture(gl.GL_TEXTURE0) gl.glBindTexture(gl.GL_TEXTURE_BUFFER, self.__data_texture.value) gl.glTexBuffer(gl.GL_TEXTURE_BUFFER, gl.GL_R32F, self.__data_buffer.value) self.__data_altered = False
def _draw_rects(shape_list: Iterable[Sprite], vertex_vbo_id: gl.GLuint, texture_coord_vbo_id: gl.GLuint): """ Draw a set of rectangles using vertex buffers. This is more efficient than drawing them individually. """ gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glEnable(gl.GL_TEXTURE_2D) # As soon as this happens, can't use drawing commands gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE) gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST) gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST) gl.glHint(gl.GL_POLYGON_SMOOTH_HINT, gl.GL_NICEST) gl.glHint(gl.GL_PERSPECTIVE_CORRECTION_HINT, gl.GL_NICEST) # gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) # gl.glMatrixMode(gl.GL_MODELVIEW) # gl.glDisable(gl.GL_BLEND) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vertex_vbo_id) gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY) gl.glEnableClientState(gl.GL_VERTEX_ARRAY) gl.glVertexPointer(2, gl.GL_FLOAT, 0, 0) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, texture_coord_vbo_id) offset = 0 for shape in shape_list: if shape.can_cache: texture_coord_vbo_id = None gl.glColor4f(1, 1, 1, shape.alpha) _render_rect_filled(shape, offset, shape.texture.texture_id, texture_coord_vbo_id) offset += 4 else: shape.draw() gl.glDisable(gl.GL_TEXTURE_2D)
def create_rects(rect_list): """ Create a vertex buffer for a set of rectangles. """ v2f = [] for shape in rect_list: v2f.extend([-shape.width / 2, -shape.height / 2, shape.width / 2, -shape.height / 2, shape.width / 2, shape.height / 2, -shape.width / 2, shape.height / 2]) vbo_id = GL.GLuint() GL.glGenBuffers(1, ctypes.pointer(vbo_id)) data2 = (GL.GLfloat*len(v2f))(*v2f) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id) GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW) shape = VertexBuffer(vbo_id, len(v2f)//2) return shape
def map(self, access=GL_READ_WRITE, target=None): """ Map the buffer locally. This increase the reading/writing speed. If the buffer was already mapped, a BufferError will be raised. Arguments: access: Buffer access. Can be GL_READ_WRITE, GL_READ_ONLY, GL_WRITE_ONLY. Default to GL_READ_WRITE target: Target to bind the buffer to. If None, use the buffer default target. Default to None. """ if self.mapped == GL_TRUE: raise BufferError("Buffer is already mapped") target = target if target is not None else self.target glBindBuffer(target, self.bid) glMapBuffer(target, access) ptr_type = POINTER(self.format.struct) ptr = c_void_p() glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, byref(ptr)) self.mapinfo = map_info(target=target, access=access, ptr=cast(ptr,ptr_type), size=self.size//sizeof(self.format.struct))
def render_rectangle_filled(shape, center_x, center_y, color, tilt_angle=0): """ Render a rectangle previously created by the ``create_rectangle`` command. """ # Set color if len(color) == 4: GL.glColor4ub(shape.color[0], shape.color[1], shape.color[2], shape.color[3]) GL.glEnable(GL.GL_BLEND) GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA) elif len(color) == 3: GL.glDisable(GL.GL_BLEND) GL.glColor4ub(shape.color[0], shape.color[1], shape.color[2], 255) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, shape.vbo_id) GL.glVertexPointer(2, GL.GL_FLOAT, 0, 0) GL.glLoadIdentity() GL.glTranslatef(center_x + shape.width / 2, center_y + shape.height / 2, 0) if tilt_angle != 0: GL.glRotatef(tilt_angle, 0, 0, 1) GL.glDrawArrays(GL.GL_QUADS, 0, shape.size)
def render_ellipse_filled(shape, center_x, center_y, color, angle=0): """ Render an ellipse previously created with the ``create_ellipse`` function. """ # Set color if len(color) == 4: GL.glColor4ub(shape.color[0], shape.color[1], shape.color[2], shape.color[3]) GL.glEnable(GL.GL_BLEND) GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA) elif len(color) == 3: GL.glDisable(GL.GL_BLEND) GL.glColor4ub(shape.color[0], shape.color[1], shape.color[2], 255) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, shape.vbo_id) GL.glVertexPointer(2, GL.GL_FLOAT, 0, 0) GL.glLoadIdentity() GL.glTranslatef(center_x, center_y, 0) if angle: GL.glRotatef(angle, 0, 0, 1) GL.glDrawArrays(GL.GL_TRIANGLE_FAN, 0, shape.size)
def __setup_geometry_buffer(self): data_buffer = ((ct.c_float*3)*36)() # {{{ vertex data for cube v0 = ( .5, .5, .5 ) v1 = ( -.5, .5, .5 ) v2 = ( -.5, -.5, .5 ) v3 = ( .5, -.5, .5 ) v4 = ( .5, .5, -.5 ) v5 = ( -.5, .5, -.5 ) v6 = ( -.5, -.5, -.5 ) v7 = ( .5, -.5, -.5 ) data_buffer[0:3] = (v4, v0, v7) data_buffer[3:6] = (v0, v3, v7) data_buffer[6:9] = (v0, v1, v2) data_buffer[9:12] = (v0, v2, v3) data_buffer[12:15] = (v5, v1, v0) data_buffer[15:18] = (v5, v0, v4) data_buffer[18:21] = (v3, v6, v7) data_buffer[21:24] = (v3, v2, v6) data_buffer[24:27] = (v2, v1, v6) data_buffer[27:30] = (v6, v1, v5) data_buffer[30:33] = (v4, v6, v5) data_buffer[33:36] = (v7, v6, v4) # }}} data_ptr = ct.cast(ct.pointer(data_buffer), ct.POINTER(ct.c_float)) # create GL buffer self.__geom_buffer = util.buffer() gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.__geom_buffer.value) gl.glBufferData(gl.GL_ARRAY_BUFFER, ct.sizeof(data_buffer), data_ptr, gl.GL_STATIC_DRAW) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)