def create_line(start_x: float, start_y: float, end_x: float, end_y: float, color: Color, line_width: float = 1) -> Shape: """ Create a line to be rendered later. This works faster than draw_line because the vertexes are only loaded to the graphics card once, rather than each frame. """ program = shader.program( vertex_shader=''' #version 330 uniform mat4 Projection; in vec2 in_vert; in vec4 in_color; out vec4 v_color; void main() { gl_Position = Projection * vec4(in_vert, 0.0, 1.0); v_color = in_color; } ''', fragment_shader=''' #version 330 in vec4 v_color; out vec4 f_color; void main() { f_color = v_color; } ''', ) buffer_type = np.dtype([('vertex', '2f4'), ('color', '4B')]) data = np.zeros(2, dtype=buffer_type) data['vertex'] = (start_x, start_y), (end_x, end_y) data['color'] = get_four_byte_color(color) vbo = shader.buffer(data.tobytes()) vao_content = [ shader.BufferDescription(vbo, '2f 4B', ('in_vert', 'in_color'), normalized=['in_color']) ] vao = shader.vertex_array(program, vao_content) with vao: program['Projection'] = get_projection().flatten() shape = Shape() shape.vao = vao shape.vbo = vbo shape.program = program shape.mode = gl.GL_LINE_STRIP shape.line_width = line_width return shape
def create_line_generic_with_colors(point_list: PointList, color_list: Iterable[Color], shape_mode: int, line_width: float=1) -> Shape: """ This function is used by ``create_line_strip`` and ``create_line_loop``, just changing the OpenGL type for the line drawing. """ program = shader.program( vertex_shader=''' #version 330 uniform mat4 Projection; in vec2 in_vert; in vec4 in_color; out vec4 v_color; void main() { gl_Position = Projection * vec4(in_vert, 0.0, 1.0); v_color = in_color; } ''', fragment_shader=''' #version 330 in vec4 v_color; out vec4 f_color; void main() { f_color = v_color; } ''', ) buffer_type = np.dtype([('vertex', '2f4'), ('color', '4B')]) data = np.zeros(len(point_list), dtype=buffer_type) data['vertex'] = point_list data['color'] = [get_four_byte_color(color) for color in color_list] vbo = shader.buffer(data.tobytes()) vao_content = [ shader.BufferDescription( vbo, '2f 4B', ('in_vert', 'in_color'), normalized=['in_color'] ) ] vao = shader.vertex_array(program, vao_content) with vao: program['Projection'] = get_projection().flatten() shape = Shape() shape.vao = vao shape.vbo = vbo shape.program = program shape.mode = shape_mode shape.line_width = line_width return shape
def _refresh_shape(self, group): # Create a buffer large enough to hold all the shapes buffers batch = self.batches[group] total_vbo_bytes = sum(s.vbo.size for s in batch.items) vbo = shader.Buffer.create_with_size(total_vbo_bytes) offset = 0 gl.glBindBuffer(gl.GL_COPY_WRITE_BUFFER, vbo.buffer_id) # Copy all the shapes buffer in our own vbo for shape in batch.items: gl.glBindBuffer(gl.GL_COPY_READ_BUFFER, shape.vbo.buffer_id) gl.glCopyBufferSubData( gl.GL_COPY_READ_BUFFER, gl.GL_COPY_WRITE_BUFFER, gl.GLintptr(0), gl.GLintptr(offset), shape.vbo.size) offset += shape.vbo.size # Create an index buffer object. It should count starting from 0. We need to # use a reset_idx to indicate that a new shape will start. reset_idx = 2 ** 32 - 1 indices = [] counter = itertools.count() for shape in batch.items: indices.extend(itertools.islice(counter, shape.vao.num_vertices)) indices.append(reset_idx) del indices[-1] indices = np.array(indices) ibo = shader.Buffer(indices.astype('i4').tobytes()) vao_content = [ shader.BufferDescription( vbo, '2f 4B', ('in_vert', 'in_color'), normalized=['in_color'] ) ] vao = shader.vertex_array(self.program, vao_content, ibo) with self.program: self.program['Projection'] = get_projection().flatten() self.program['Position'] = [self.center_x, self.center_y] self.program['Angle'] = self.angle batch.shape.vao = vao batch.shape.vbo = vbo batch.shape.ibo = ibo batch.shape.program = self.program mode, line_width = group batch.shape.mode = mode batch.shape.line_width = line_width