def _create_rects(rect_list: Iterable[Sprite]) -> List[float]: """ 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]) x1 = -shape.width / 2 + shape.center_x x2 = shape.width / 2 + shape.center_x y1 = -shape.height / 2 + shape.center_y y2 = shape.height / 2 + shape.center_y p1 = x1, y1 p2 = x2, y1 p3 = x2, y2 p4 = x1, y2 if shape.angle: p1 = rotate_point(p1[0], p1[1], shape.center_x, shape.center_y, shape.angle) p2 = rotate_point(p2[0], p2[1], shape.center_x, shape.center_y, shape.angle) p3 = rotate_point(p3[0], p3[1], shape.center_x, shape.center_y, shape.angle) p4 = rotate_point(p4[0], p4[1], shape.center_x, shape.center_y, shape.angle) v2f.extend([p1[0], p1[1], p2[0], p2[1], p3[0], p3[1], p4[0], p4[1]]) return v2f
def get_rectangle_points(center_x: float, center_y: float, width: float, height: float, tilt_angle: float = 0) -> PointList: """ Utility function that will return all four coordinate points of a rectangle given the x, y center, width, height, and rotation. """ x1 = -width / 2 + center_x y1 = -height / 2 + center_y x2 = -width / 2 + center_x y2 = height / 2 + center_y x3 = width / 2 + center_x y3 = height / 2 + center_y x4 = width / 2 + center_x y4 = -height / 2 + center_y if tilt_angle: x1, y1 = rotate_point(x1, y1, center_x, center_y, tilt_angle) x2, y2 = rotate_point(x2, y2, center_x, center_y, tilt_angle) x3, y3 = rotate_point(x3, y3, center_x, center_y, tilt_angle) x4, y4 = rotate_point(x4, y4, center_x, center_y, tilt_angle) data = [(x1, y1), (x2, y2), (x3, y3), (x4, y4)] return data
def get_points(self) -> Tuple[Tuple[float, float], ...]: """ Get the corner points for the rect that makes up the sprite. """ if self._point_list_cache is not None: return self._point_list_cache if self._points is not None: point_list = [] for point_idx in range(len(self._points)): point = (self._points[point_idx][0] + self.center_x, self._points[point_idx][1] + self.center_y) point_list.append(point) self._point_list_cache = tuple(point_list) else: x1, y1 = rotate_point(self.center_x - self.width / 2, self.center_y - self.height / 2, self.center_x, self.center_y, self.angle) x2, y2 = rotate_point(self.center_x + self.width / 2, self.center_y - self.height / 2, self.center_x, self.center_y, self.angle) x3, y3 = rotate_point(self.center_x + self.width / 2, self.center_y + self.height / 2, self.center_x, self.center_y, self.angle) x4, y4 = rotate_point(self.center_x - self.width / 2, self.center_y + self.height / 2, self.center_x, self.center_y, self.angle) self._point_list_cache = ((x1, y1), (x2, y2), (x3, y3), (x4, y4)) return self._point_list_cache
def create_ellipse_filled_with_colors(center_x: float, center_y: float, width: float, height: float, outside_color: Color, inside_color: Color, tilt_angle: float = 0, num_segments=32) -> Shape: """ Draw an ellipse, and specify inside/outside color. Used for doing gradients. """ # Create an array with the vertex data # Create an array with the vertex point_list point_list = [] point_list.append((center_x, center_y)) for segment in range(num_segments): theta = 2.0 * 3.1415926 * segment / num_segments x = width * math.cos(theta) + center_x y = height * math.sin(theta) + center_y if tilt_angle: x, y = rotate_point(x, y, center_x, center_y, tilt_angle) point_list.append((x, y)) point_list.append(point_list[1]) color_list = [inside_color] + [outside_color] * (num_segments + 1) return create_line_generic_with_colors(point_list, color_list, gl.GL_TRIANGLE_FAN)
def get_points(self) -> Tuple[Tuple[float, float]]: """ Get the corner points for the rect that makes up the sprite. >>> import arcade >>> empty_sprite = arcade.Sprite() >>> my_points = (0,0),(1,1),(0,1),(1,0) >>> empty_sprite.set_points(my_points) >>> empty_sprite.get_points() ((0, 0), (1, 1), (0, 1), (1, 0)) """ if self._point_list_cache is not None: return self._point_list_cache if self._points is not None: point_list = [] for point in range(len(self._points)): point = (self._points[point][0] + self.center_x, self._points[point][1] + self.center_y) point_list.append(point) self._point_list_cache = tuple(point_list) else: x1, y1 = rotate_point(self.center_x - self.width / 2, self.center_y - self.height / 2, self.center_x, self.center_y, self.angle) x2, y2 = rotate_point(self.center_x + self.width / 2, self.center_y - self.height / 2, self.center_x, self.center_y, self.angle) x3, y3 = rotate_point(self.center_x + self.width / 2, self.center_y + self.height / 2, self.center_x, self.center_y, self.angle) x4, y4 = rotate_point(self.center_x - self.width / 2, self.center_y + self.height / 2, self.center_x, self.center_y, self.angle) self._point_list_cache = ((x1, y1), (x2, y2), (x3, y3), (x4, y4)) self.add_spatial_hashes() return self._point_list_cache
def create_rectangle(center_x: float, center_y: float, width: float, height: float, color: Color, border_width: float = 1, tilt_angle: float = 0, filled=True) -> Shape: """ This function creates a rectangle using a vertex buffer object. Creating the rectangle, and then later drawing it with ``render_rectangle`` is faster than calling ``draw_rectangle``. Args: center_x: center_y: width: height: color: border_width: tilt_angle: filled: Returns: """ data: List[Point] = cast(List[Point], get_rectangle_points(center_x, center_y, width, height, tilt_angle)) if filled: shape_mode = gl.GL_TRIANGLE_STRIP data[-2:] = reversed(data[-2:]) else: i_lb = center_x - width / 2 + border_width / 2, center_y - height / 2 + border_width / 2 i_rb = center_x + width / 2 - border_width / 2, center_y - height / 2 + border_width / 2 i_rt = center_x + width / 2 - border_width / 2, center_y + height / 2 - border_width / 2 i_lt = center_x - width / 2 + border_width / 2, center_y + height / 2 - border_width / 2 o_lb = center_x - width / 2 - border_width / 2, center_y - height / 2 - border_width / 2 o_rb = center_x + width / 2 + border_width / 2, center_y - height / 2 - border_width / 2 o_rt = center_x + width / 2 + border_width / 2, center_y + height / 2 + border_width / 2 o_lt = center_x - width / 2 - border_width / 2, center_y + height / 2 + border_width / 2 data = [o_lt, i_lt, o_rt, i_rt, o_rb, i_rb, o_lb, i_lb, o_lt, i_lt] if tilt_angle != 0: point_list_2: List[Point] = [] for point in data: new_point = rotate_point(point[0], point[1], center_x, center_y, tilt_angle) point_list_2.append(new_point) data = point_list_2 border_width = 1 shape_mode = gl.GL_TRIANGLE_STRIP # _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_STRIP) # shape_mode = gl.GL_LINE_STRIP # data.append(data[0]) shape = create_line_generic(data, color, shape_mode, border_width) return shape
def create_ellipse(center_x: float, center_y: float, width: float, height: float, color: Color, border_width: float=1, tilt_angle: float=0, num_segments=32, filled=True) -> Shape: """ 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. Note: This can't be unit tested on Appveyor because its support for OpenGL is poor. >>> import arcade >>> arcade.open_window(800, 600, "Drawing Example") >>> arcade.start_render() >>> rect = arcade.create_ellipse(50, 50, 20, 20, arcade.color.RED, 2, 45) >>> arcade.render(rect) >>> arcade.finish_render() >>> arcade.quick_run(0.25) """ # Create an array with the vertex point_list point_list = [] for segment in range(num_segments): theta = 2.0 * 3.1415926 * segment / num_segments x = width * math.cos(theta) + center_x y = height * math.sin(theta) + center_y if tilt_angle: x, y = rotate_point(x, y, center_x, center_y, tilt_angle) point_list.append((x, y)) if filled: half = len(point_list) // 2 interleaved = itertools.chain.from_iterable( itertools.zip_longest(point_list[:half], reversed(point_list[half:])) ) point_list = [p for p in interleaved if p is not None] shape_mode = gl.GL_TRIANGLE_STRIP else: point_list.append(point_list[0]) shape_mode = gl.GL_LINE_STRIP return create_line_generic(point_list, color, shape_mode, border_width)
def create_ellipse_filled_with_colors(center_x: float, center_y: float, width: float, height: float, outside_color: Color, inside_color: Color, tilt_angle: float=0, num_segments=32) -> Shape: """ >>> import arcade >>> arcade.open_window(800,600,"Drawing Example") >>> point_list = [(0, 0), (100, 0), (100, 100)] >>> color_list = [arcade.color.RED, arcade.color.BLUE, arcade.color.GREEN] >>> my_shape = arcade.create_ellipse_filled_with_colors(100, 100, 50, 50, arcade.color.AFRICAN_VIOLET, arcade.color.ALABAMA_CRIMSON, tilt_angle=45) >>> my_shape_list = ShapeElementList() >>> my_shape_list.append(my_shape) >>> my_shape_list.draw() >>> arcade.finish_render() >>> arcade.quick_run(0.25) """ # Create an array with the vertex data # Create an array with the vertex point_list point_list = [] point_list.append((center_x, center_y)) for segment in range(num_segments): theta = 2.0 * 3.1415926 * segment / num_segments x = width * math.cos(theta) + center_x y = height * math.sin(theta) + center_y if tilt_angle: x, y = rotate_point(x, y, center_x, center_y, tilt_angle) point_list.append((x, y)) point_list.append(point_list[1]) color_list = [inside_color] + [outside_color] * (num_segments + 1) return create_line_generic_with_colors(point_list, color_list, gl.GL_TRIANGLE_FAN)
def create_ellipse_filled_with_colors(center_x: float, center_y: float, width: float, height: float, outside_color: Color, inside_color: Color, tilt_angle: float=0, num_segments=32) -> VertexBuffer: """ >>> import arcade >>> arcade.open_window(800,600,"Drawing Example") >>> point_list = [(0, 0), (100, 0), (100, 100)] >>> color_list = [arcade.color.RED, arcade.color.BLUE, arcade.color.GREEN] >>> my_shape = arcade.create_ellipse_filled_with_colors(100, 100, 50, 50, arcade.color.AFRICAN_VIOLET, arcade.color.ALABAMA_CRIMSON, tilt_angle=45) >>> my_shape_list = ShapeElementList() >>> my_shape_list.append(my_shape) >>> my_shape_list.draw() >>> arcade.finish_render() >>> arcade.quick_run(0.25) """ # Create an array with the vertex data vertex_data = [] color_data = [] vertex_data.extend((center_x, center_y)) color_data.append((inside_color)) for segment in range(num_segments + 1): theta = 2.0 * 3.1415926 * segment / num_segments x = width * math.cos(theta) + center_x y = height * math.sin(theta) + center_y if tilt_angle: x, y = rotate_point(x, y, center_x, center_y, tilt_angle) vertex_data.extend([x, y]) color_data.append((outside_color)) # Create an id for our vertex buffer vbo_vertex_id = gl.GLuint() gl.glGenBuffers(1, ctypes.pointer(vbo_vertex_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(vertex_data))(*vertex_data) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo_vertex_id) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, gl.GL_STATIC_DRAW) shape_mode = gl.GL_TRIANGLE_FAN # shape_mode = gl.GL_LINE_LOOP # Colors color_data = _fix_color_list(color_data) vbo_color_id = gl.GLuint() gl.glGenBuffers(1, ctypes.pointer(vbo_color_id)) gl_color_list = (gl.GLfloat * len(color_data))(*color_data) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo_color_id) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(gl_color_list), gl_color_list, gl.GL_STATIC_DRAW) shape = VertexBuffer(vbo_vertex_id, len(vertex_data) // 2, shape_mode, vbo_color_id=vbo_color_id) return shape
def create_ellipse(center_x: float, center_y: float, width: float, height: float, color: Color, border_width: float=0, tilt_angle: float=0, num_segments=32, filled=True) -> VertexBuffer: """ 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. Note: This can't be unit tested on Appveyor because its support for OpenGL is poor. >>> import arcade >>> arcade.open_window(800, 600, "Drawing Example") >>> arcade.start_render() >>> rect = arcade.create_ellipse(50, 50, 20, 20, arcade.color.RED, 2, 45) >>> arcade.render(rect) >>> arcade.finish_render() >>> arcade.quick_run(0.25) """ # Create an array with the vertex data data = [] for segment in range(num_segments + 1): theta = 2.0 * 3.1415926 * segment / num_segments x = width * math.cos(theta) + center_x y = height * math.sin(theta) + center_y if tilt_angle: x, y = rotate_point(x, y, center_x, center_y, tilt_angle) data.extend([x, y]) # Create an id for our vertex buffer 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) if filled: shape_mode = gl.GL_TRIANGLE_FAN else: shape_mode = gl.GL_LINE_LOOP shape = VertexBuffer(vbo_id, len(data) // 2, shape_mode) shape.color = color shape.line_width = border_width return shape