예제 #1
0
def _create_rects(rect_list: Iterable[Sprite]) -> List[float]:
    """
    Create a vertex buffer for a set of rectangles.
    """

    v2f = []
    for shape in rect_list:
        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
예제 #2
0
    def get_adjusted_hit_box(self) -> List[List[float]]:
        """
        Get the points that make up the hit box for the rect that makes up the
        sprite, including rotation and scaling.
        """

        # If we've already calculated the adjusted hit box, use the cached version
        if self._point_list_cache is not None:
            return self._point_list_cache

        # If there is no hitbox, use the width/height to get one
        if self._points is None and self._texture:
            self._points = self._texture.hit_box_points

        if self._points is None and self._width:
            x1, y1 = -self._width / 2, -self._height / 2
            x2, y2 = +self._width / 2, -self._height / 2
            x3, y3 = +self._width / 2, +self._height / 2
            x4, y4 = -self._width / 2, +self._height / 2

            self._points = [[x1, y1], [x2, y2], [x3, y3], [x4, y4]]

        if self._points is None and self.texture is not None:
            self._points = self.texture.hit_box_points

        if self._points is None:
            raise ValueError(
                "Error trying to get the hit box of a sprite, when no hit box is set.\nPlease make sure the "
                "Sprite.texture is set to a texture before trying to draw or do collision testing.\n"
                "Alternatively, manually call Sprite.set_hit_box with points for your hitbox."
            )

        # Adjust the hitbox
        point_list = []
        for point in self._points:
            # Get a copy of the point
            point = [point[0], point[1]]

            # Scale the point
            if self.scale != 1:
                point[0] *= self.scale
                point[1] *= self.scale

            # Rotate the point
            if self.angle:
                point = rotate_point(point[0], point[1], 0, 0, self.angle)

            # Offset the point
            point = [point[0] + self.center_x, point[1] + self.center_y]
            point_list.append(point)

        # Cache the results
        self._point_list_cache = point_list

        # if self.texture:
        #     print(self.texture.name, self._point_list_cache)

        return self._point_list_cache
예제 #3
0
def get_rectangle_points(center_x: float,
                         center_y: float,
                         width: float,
                         height: float,
                         tilt_angle: float = 0):
    """
    Utility function that will return all four coordinate points of a
    rectangle given the center_x, center_y, width, height, and rotation.

    Args:
        center_x:
        center_y:
        width:
        height:
        tilt_angle:

    Returns:

    """
    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
예제 #4
0
def draw_ellipse(center_x: float,
                 center_y: float,
                 width: float,
                 height: float,
                 color: Color,
                 border_width: float = 1,
                 tilt_angle: float = 0,
                 num_segments: int = 32,
                 filled=True):
    """
    Draw an ellipse.
    Note: This can't be unit tested on Appveyor because its support for OpenGL is
    poor.
    """
    # 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:
        id = f"ellipse-filled-{center_x}-{center_y}-{width}-{height}-{color}-{border_width}-{tilt_angle}-{num_segments}"
        if id not in buffered_shapes.keys():
            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
            shape = _create_line_generic(point_list, color, shape_mode,
                                         border_width)
            buffered_shapes[id] = shape
        buffered_shapes[id].draw()
    else:
        id = f"ellipse-empty-{center_x}-{center_y}-{width}-{height}-{color}-{border_width}-{tilt_angle}-{num_segments}"
        if id not in buffered_shapes.keys():
            point_list.append(point_list[0])
            shape_mode = gl.GL_LINE_STRIP
            shape = _create_line_generic(point_list, color, shape_mode,
                                         border_width)
            buffered_shapes[id] = shape
        buffered_shapes[id].draw()
예제 #5
0
def draw_arc_filled(center_x: float,
                    center_y: float,
                    width: float,
                    height: float,
                    color: Color,
                    start_angle: float,
                    end_angle: float,
                    tilt_angle: float = 0,
                    num_segments: int = 128):
    """
    Draw a filled in arc. Useful for drawing pie-wedges, or Pac-Man.

    :param float center_x: x position that is the center of the arc.
    :param float center_y: y position that is the center of the arc.
    :param float width: width of the arc.
    :param float height: height of the arc.
    :param Color color: color, specified in a list of 3 or 4 bytes in RGB or
         RGBA format.
    :param float start_angle: start angle of the arc in degrees.
    :param float end_angle: end angle of the arc in degrees.
    :param float tilt_angle: angle the arc is tilted.
    :param float num_segments: Number of line segments used to draw arc.
    """
    unrotated_point_list = [[0.0, 0.0]]

    start_segment = int(start_angle / 360 * num_segments)
    end_segment = int(end_angle / 360 * num_segments)

    for segment in range(start_segment, end_segment + 1):
        theta = 2.0 * 3.1415926 * segment / num_segments

        x = width * math.cos(theta) / 2
        y = height * math.sin(theta) / 2

        unrotated_point_list.append([x, y])

    if tilt_angle == 0:
        uncentered_point_list = unrotated_point_list
    else:
        uncentered_point_list = []
        for point in unrotated_point_list:
            uncentered_point_list.append(
                rotate_point(point[0], point[1], 0, 0, tilt_angle))

    point_list = []
    for point in uncentered_point_list:
        point_list.append((point[0] + center_x, point[1] + center_y))

    _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_FAN)
예제 #6
0
def draw_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: int = 32):
    """
    Draw an ellipse, and specify inside/outside color. Used for doing gradients.

    :param float center_x:
    :param float center_y:
    :param float width:
    :param float height:
    :param Color outside_color:
    :param float inside_color:
    :param float tilt_angle:
    :param int num_segments:

    :Returns Shape:

    """

    # Create an array with the vertex data
    # Create an array with the vertex point_list
    point_list = [(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)
    id = f"ellipse-filled-with-colors-{point_list}-{color_list}"
    if id not in buffered_shapes.keys():
        shape = _create_line_generic_with_colors(point_list, color_list,
                                                 gl.GL_TRIANGLE_FAN)
        buffered_shapes[id] = shape
    buffered_shapes[id].draw()
예제 #7
0
def draw_rectangle(center_x: float,
                   center_y: float,
                   width: float,
                   height: float,
                   color: Color,
                   border_width: float = 1,
                   tilt_angle: float = 0,
                   filled=True):
    """
    Draw a 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:])
        id = f"rect-filled-{data}-{color}-{border_width}"
    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])s

        id = f"rect-empty-{data}-{color}-{border_width}"

    if id not in buffered_shapes.keys():
        shape = _create_line_generic(data, color, shape_mode, border_width)
        buffered_shapes[id] = shape
    buffered_shapes[id].draw()
예제 #8
0
def draw_arc_outline(center_x: float,
                     center_y: float,
                     width: float,
                     height: float,
                     color: Color,
                     start_angle: float,
                     end_angle: float,
                     border_width: float = 1,
                     tilt_angle: float = 0,
                     num_segments: int = 128):
    """
    Draw the outside edge of an arc. Useful for drawing curved lines.

    :param float center_x: x position that is the center of the arc.
    :param float center_y: y position that is the center of the arc.
    :param float width: width of the arc.
    :param float height: height of the arc.
    :param Color color: color, specified in a list of 3 or 4 bytes in RGB or
         RGBA format.
    :param float start_angle: start angle of the arc in degrees.
    :param float end_angle: end angle of the arc in degrees.
    :param float border_width: width of line in pixels.
    :param float tilt_angle: angle the arc is tilted.
    :param int num_segments: float of triangle segments that make up this
         circle. Higher is better quality, but slower render time.
    """
    unrotated_point_list = []

    start_segment = int(start_angle / 360 * num_segments)
    end_segment = int(end_angle / 360 * num_segments)

    inside_width = (width - border_width / 2) / 2
    outside_width = (width + border_width / 2) / 2
    inside_height = (height - border_width / 2) / 2
    outside_height = (height + border_width / 2) / 2

    for segment in range(start_segment, end_segment + 1):
        theta = 2.0 * math.pi * segment / num_segments

        x1 = inside_width * math.cos(theta)
        y1 = inside_height * math.sin(theta)

        x2 = outside_width * math.cos(theta)
        y2 = outside_height * math.sin(theta)

        unrotated_point_list.append([x1, y1])
        unrotated_point_list.append([x2, y2])

    if tilt_angle == 0:
        uncentered_point_list = unrotated_point_list
    else:
        uncentered_point_list = []
        for point in unrotated_point_list:
            uncentered_point_list.append(
                rotate_point(point[0], point[1], 0, 0, tilt_angle))

    point_list = []
    for point in uncentered_point_list:
        point_list.append((point[0] + center_x, point[1] + center_y))

    _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_STRIP)