6442 lines
240 KiB
Python
6442 lines
240 KiB
Python
from collections import OrderedDict
|
|
import copy
|
|
import platform
|
|
import random
|
|
import unittest
|
|
import sys
|
|
|
|
import pygame
|
|
from pygame.locals import *
|
|
from pygame.math import Vector2
|
|
|
|
|
|
IS_PYPY = "PyPy" == platform.python_implementation()
|
|
|
|
|
|
def random_mask(size=(100, 100)):
|
|
"""random_mask(size=(100,100)): return Mask
|
|
Create a mask of the given size, with roughly half the bits set at random."""
|
|
m = pygame.Mask(size)
|
|
for i in range(size[0] * size[1] // 2):
|
|
x, y = random.randint(0, size[0] - 1), random.randint(0, size[1] - 1)
|
|
m.set_at((x, y))
|
|
return m
|
|
|
|
|
|
def maskFromSurface(surface, threshold=127):
|
|
mask = pygame.Mask(surface.get_size())
|
|
key = surface.get_colorkey()
|
|
if key:
|
|
for y in range(surface.get_height()):
|
|
for x in range(surface.get_width()):
|
|
if surface.get_at((x + 0.1, y + 0.1)) != key:
|
|
mask.set_at((x, y), 1)
|
|
else:
|
|
for y in range(surface.get_height()):
|
|
for x in range(surface.get_width()):
|
|
if surface.get_at((x, y))[3] > threshold:
|
|
mask.set_at((x, y), 1)
|
|
return mask
|
|
|
|
|
|
def create_bounding_rect(points):
|
|
"""Creates a bounding rect from the given points."""
|
|
xmin = xmax = points[0][0]
|
|
ymin = ymax = points[0][1]
|
|
|
|
for x, y in points[1:]:
|
|
xmin = min(x, xmin)
|
|
xmax = max(x, xmax)
|
|
ymin = min(y, ymin)
|
|
ymax = max(y, ymax)
|
|
|
|
return pygame.Rect((xmin, ymin), (xmax - xmin + 1, ymax - ymin + 1))
|
|
|
|
|
|
def zero_size_pairs(width, height):
|
|
"""Creates a generator which yields pairs of sizes.
|
|
|
|
For each pair of sizes at least one of the sizes will have a 0 in it.
|
|
"""
|
|
sizes = ((width, height), (width, 0), (0, height), (0, 0))
|
|
|
|
return ((a, b) for a in sizes for b in sizes if 0 in a or 0 in b)
|
|
|
|
|
|
def corners(mask):
|
|
"""Returns a tuple with the corner positions of the given mask.
|
|
|
|
Clockwise from the top left corner.
|
|
"""
|
|
width, height = mask.get_size()
|
|
return ((0, 0), (width - 1, 0), (width - 1, height - 1), (0, height - 1))
|
|
|
|
|
|
def off_corners(rect):
|
|
"""Returns a tuple with the positions off of the corners of the given rect.
|
|
|
|
Clockwise from the top left corner.
|
|
"""
|
|
return (
|
|
(rect.left - 1, rect.top),
|
|
(rect.left - 1, rect.top - 1),
|
|
(rect.left, rect.top - 1),
|
|
(rect.right - 1, rect.top - 1),
|
|
(rect.right, rect.top - 1),
|
|
(rect.right, rect.top),
|
|
(rect.right, rect.bottom - 1),
|
|
(rect.right, rect.bottom),
|
|
(rect.right - 1, rect.bottom),
|
|
(rect.left, rect.bottom),
|
|
(rect.left - 1, rect.bottom),
|
|
(rect.left - 1, rect.bottom - 1),
|
|
)
|
|
|
|
|
|
def assertSurfaceFilled(testcase, surface, expected_color, area_rect=None):
|
|
"""Checks to see if the given surface is filled with the given color.
|
|
|
|
If an area_rect is provided, only check that area of the surface.
|
|
"""
|
|
if area_rect is None:
|
|
x_range = range(surface.get_width())
|
|
y_range = range(surface.get_height())
|
|
else:
|
|
area_rect.normalize()
|
|
area_rect = area_rect.clip(surface.get_rect())
|
|
x_range = range(area_rect.left, area_rect.right)
|
|
y_range = range(area_rect.top, area_rect.bottom)
|
|
|
|
surface.lock() # Lock for possible speed up.
|
|
for pos in ((x, y) for y in y_range for x in x_range):
|
|
testcase.assertEqual(surface.get_at(pos), expected_color, pos)
|
|
surface.unlock()
|
|
|
|
|
|
def assertSurfaceFilledIgnoreArea(testcase, surface, expected_color, ignore_rect):
|
|
"""Checks if the surface is filled with the given color. The
|
|
ignore_rect area is not checked.
|
|
"""
|
|
x_range = range(surface.get_width())
|
|
y_range = range(surface.get_height())
|
|
ignore_rect.normalize()
|
|
|
|
surface.lock() # Lock for possible speed up.
|
|
for pos in ((x, y) for y in y_range for x in x_range):
|
|
if not ignore_rect.collidepoint(pos):
|
|
testcase.assertEqual(surface.get_at(pos), expected_color, pos)
|
|
surface.unlock()
|
|
|
|
|
|
def assertMaskEqual(testcase, m1, m2, msg=None):
|
|
"""Checks to see if the 2 given masks are equal."""
|
|
m1_count = m1.count()
|
|
|
|
testcase.assertEqual(m1.get_size(), m2.get_size(), msg=msg)
|
|
testcase.assertEqual(m1_count, m2.count(), msg=msg)
|
|
testcase.assertEqual(m1_count, m1.overlap_area(m2, (0, 0)), msg=msg)
|
|
|
|
# This can be used to help debug exact locations.
|
|
##for i in range(m1.get_size()[0]):
|
|
## for j in range(m1.get_size()[1]):
|
|
## testcase.assertEqual(m1.get_at((i, j)), m2.get_at((i, j)))
|
|
|
|
|
|
# @unittest.skipIf(IS_PYPY, "pypy has lots of mask failures") # TODO
|
|
class MaskTypeTest(unittest.TestCase):
|
|
ORIGIN_OFFSETS = (
|
|
(0, 0),
|
|
(0, 1),
|
|
(1, 1),
|
|
(1, 0),
|
|
(1, -1),
|
|
(0, -1),
|
|
(-1, -1),
|
|
(-1, 0),
|
|
(-1, 1),
|
|
)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_mask(self):
|
|
"""Ensure masks are created correctly without fill parameter."""
|
|
expected_count = 0
|
|
expected_size = (11, 23)
|
|
|
|
mask1 = pygame.mask.Mask(expected_size)
|
|
mask2 = pygame.mask.Mask(size=expected_size)
|
|
|
|
self.assertIsInstance(mask1, pygame.mask.Mask)
|
|
self.assertEqual(mask1.count(), expected_count)
|
|
self.assertEqual(mask1.get_size(), expected_size)
|
|
|
|
self.assertIsInstance(mask2, pygame.mask.Mask)
|
|
self.assertEqual(mask2.count(), expected_count)
|
|
self.assertEqual(mask2.get_size(), expected_size)
|
|
|
|
def test_mask__negative_size(self):
|
|
"""Ensure the mask constructor handles negative sizes correctly."""
|
|
for size in ((1, -1), (-1, 1), (-1, -1)):
|
|
with self.assertRaises(ValueError):
|
|
mask = pygame.Mask(size)
|
|
|
|
def test_mask__fill_kwarg(self):
|
|
"""Ensure masks are created correctly using the fill keyword."""
|
|
width, height = 37, 47
|
|
expected_size = (width, height)
|
|
fill_counts = {True: width * height, False: 0}
|
|
|
|
for fill, expected_count in fill_counts.items():
|
|
msg = f"fill={fill}"
|
|
|
|
mask = pygame.mask.Mask(expected_size, fill=fill)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.count(), expected_count, msg)
|
|
self.assertEqual(mask.get_size(), expected_size, msg)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_mask__fill_kwarg_bit_boundaries(self):
|
|
"""Ensures masks are created correctly using the fill keyword
|
|
over a range of sizes.
|
|
|
|
Tests masks of different sizes, including:
|
|
-masks 31 to 33 bits wide (32 bit boundaries)
|
|
-masks 63 to 65 bits wide (64 bit boundaries)
|
|
"""
|
|
for height in range(1, 4):
|
|
for width in range(1, 66):
|
|
expected_count = width * height
|
|
expected_size = (width, height)
|
|
msg = f"size={expected_size}"
|
|
|
|
mask = pygame.mask.Mask(expected_size, fill=True)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.count(), expected_count, msg)
|
|
self.assertEqual(mask.get_size(), expected_size, msg)
|
|
|
|
def test_mask__fill_arg(self):
|
|
"""Ensure masks are created correctly using a fill arg."""
|
|
width, height = 59, 71
|
|
expected_size = (width, height)
|
|
fill_counts = {True: width * height, False: 0}
|
|
|
|
for fill, expected_count in fill_counts.items():
|
|
msg = f"fill={fill}"
|
|
|
|
mask = pygame.mask.Mask(expected_size, fill)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.count(), expected_count, msg)
|
|
self.assertEqual(mask.get_size(), expected_size, msg)
|
|
|
|
def test_mask__size_kwarg(self):
|
|
"""Ensure masks are created correctly using the size keyword."""
|
|
width, height = 73, 83
|
|
expected_size = (width, height)
|
|
fill_counts = {True: width * height, False: 0}
|
|
|
|
for fill, expected_count in fill_counts.items():
|
|
msg = f"fill={fill}"
|
|
|
|
mask1 = pygame.mask.Mask(fill=fill, size=expected_size)
|
|
mask2 = pygame.mask.Mask(size=expected_size, fill=fill)
|
|
|
|
self.assertIsInstance(mask1, pygame.mask.Mask, msg)
|
|
self.assertIsInstance(mask2, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask1.count(), expected_count, msg)
|
|
self.assertEqual(mask2.count(), expected_count, msg)
|
|
self.assertEqual(mask1.get_size(), expected_size, msg)
|
|
self.assertEqual(mask2.get_size(), expected_size, msg)
|
|
|
|
def test_copy(self):
|
|
"""Ensures copy works correctly with some bits set and unset."""
|
|
# Test different widths and heights.
|
|
for width in (31, 32, 33, 63, 64, 65):
|
|
for height in (31, 32, 33, 63, 64, 65):
|
|
mask = pygame.mask.Mask((width, height))
|
|
|
|
# Create a checkerboard pattern of set/unset bits.
|
|
for x in range(width):
|
|
for y in range(x & 1, height, 2):
|
|
mask.set_at((x, y))
|
|
|
|
# Test both the copy() and __copy__() methods.
|
|
for mask_copy in (mask.copy(), copy.copy(mask)):
|
|
self.assertIsInstance(mask_copy, pygame.mask.Mask)
|
|
self.assertIsNot(mask_copy, mask)
|
|
assertMaskEqual(self, mask_copy, mask)
|
|
|
|
def test_copy__full(self):
|
|
"""Ensures copy works correctly on a filled masked."""
|
|
# Test different widths and heights.
|
|
for width in (31, 32, 33, 63, 64, 65):
|
|
for height in (31, 32, 33, 63, 64, 65):
|
|
mask = pygame.mask.Mask((width, height), fill=True)
|
|
|
|
# Test both the copy() and __copy__() methods.
|
|
for mask_copy in (mask.copy(), copy.copy(mask)):
|
|
self.assertIsInstance(mask_copy, pygame.mask.Mask)
|
|
self.assertIsNot(mask_copy, mask)
|
|
assertMaskEqual(self, mask_copy, mask)
|
|
|
|
def test_copy__empty(self):
|
|
"""Ensures copy works correctly on an empty mask."""
|
|
for width in (31, 32, 33, 63, 64, 65):
|
|
for height in (31, 32, 33, 63, 64, 65):
|
|
mask = pygame.mask.Mask((width, height))
|
|
|
|
# Test both the copy() and __copy__() methods.
|
|
for mask_copy in (mask.copy(), copy.copy(mask)):
|
|
self.assertIsInstance(mask_copy, pygame.mask.Mask)
|
|
self.assertIsNot(mask_copy, mask)
|
|
assertMaskEqual(self, mask_copy, mask)
|
|
|
|
def test_copy__independent(self):
|
|
"""Ensures copy makes an independent copy of the mask."""
|
|
mask_set_pos = (64, 1)
|
|
mask_copy_set_pos = (64, 2)
|
|
mask = pygame.mask.Mask((65, 3))
|
|
|
|
# Test both the copy() and __copy__() methods.
|
|
mask_copies = (mask.copy(), copy.copy(mask))
|
|
mask.set_at(mask_set_pos)
|
|
|
|
for mask_copy in mask_copies:
|
|
mask_copy.set_at(mask_copy_set_pos)
|
|
|
|
self.assertIsNot(mask_copy, mask)
|
|
self.assertNotEqual(
|
|
mask_copy.get_at(mask_set_pos), mask.get_at(mask_set_pos)
|
|
)
|
|
self.assertNotEqual(
|
|
mask_copy.get_at(mask_copy_set_pos), mask.get_at(mask_copy_set_pos)
|
|
)
|
|
|
|
def test_get_size(self):
|
|
"""Ensure a mask's size is correctly retrieved."""
|
|
expected_size = (93, 101)
|
|
mask = pygame.mask.Mask(expected_size)
|
|
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
def test_get_rect(self):
|
|
"""Ensures get_rect works correctly."""
|
|
expected_rect = pygame.Rect((0, 0), (11, 13))
|
|
|
|
# Test on full and empty masks.
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(expected_rect.size, fill=fill)
|
|
|
|
rect = mask.get_rect()
|
|
|
|
self.assertEqual(rect, expected_rect)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_get_rect__one_kwarg(self):
|
|
"""Ensures get_rect supports a single rect attribute kwarg.
|
|
|
|
Tests all the rect attributes.
|
|
"""
|
|
# Rect attributes that take a single value.
|
|
RECT_SINGLE_VALUE_ATTRIBUTES = (
|
|
"x",
|
|
"y",
|
|
"top",
|
|
"left",
|
|
"bottom",
|
|
"right",
|
|
"centerx",
|
|
"centery",
|
|
"width",
|
|
"height",
|
|
"w",
|
|
"h",
|
|
)
|
|
|
|
# Rect attributes that take 2 values.
|
|
RECT_DOUBLE_VALUE_ATTRIBUTES = (
|
|
"topleft",
|
|
"bottomleft",
|
|
"topright",
|
|
"bottomright",
|
|
"midtop",
|
|
"midleft",
|
|
"midbottom",
|
|
"midright",
|
|
"center",
|
|
"size",
|
|
)
|
|
|
|
# Testing ints/floats and tuples/lists/Vector2s.
|
|
# {attribute_names : attribute_values}
|
|
rect_attributes = {
|
|
RECT_SINGLE_VALUE_ATTRIBUTES: (3, 5.1),
|
|
RECT_DOUBLE_VALUE_ATTRIBUTES: ((1, 2.2), [2.3, 3], Vector2(0, 1)),
|
|
}
|
|
|
|
size = (7, 3)
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
for attributes, values in rect_attributes.items():
|
|
for attribute in attributes:
|
|
for value in values:
|
|
expected_rect = pygame.Rect((0, 0), size)
|
|
setattr(expected_rect, attribute, value)
|
|
|
|
rect = mask.get_rect(**{attribute: value})
|
|
|
|
self.assertEqual(rect, expected_rect)
|
|
|
|
def test_get_rect__multiple_kwargs(self):
|
|
"""Ensures get_rect supports multiple rect attribute kwargs."""
|
|
mask = pygame.mask.Mask((5, 4))
|
|
expected_rect = pygame.Rect((0, 0), (0, 0))
|
|
kwargs = {"x": 7.1, "top": -1, "size": Vector2(2, 3.2)}
|
|
|
|
for attrib, value in kwargs.items():
|
|
setattr(expected_rect, attrib, value)
|
|
|
|
rect = mask.get_rect(**kwargs)
|
|
|
|
self.assertEqual(rect, expected_rect)
|
|
|
|
def test_get_rect__no_arg_support(self):
|
|
"""Ensures get_rect only supports kwargs."""
|
|
mask = pygame.mask.Mask((4, 5))
|
|
|
|
with self.assertRaises(TypeError):
|
|
rect = mask.get_rect(3)
|
|
|
|
with self.assertRaises(TypeError):
|
|
rect = mask.get_rect((1, 2))
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_get_rect__invalid_kwarg_name(self):
|
|
"""Ensures get_rect detects invalid kwargs."""
|
|
mask = pygame.mask.Mask((1, 2))
|
|
|
|
with self.assertRaises(AttributeError):
|
|
rect = mask.get_rect(righte=11)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
rect = mask.get_rect(toplef=(1, 1))
|
|
|
|
with self.assertRaises(AttributeError):
|
|
rect = mask.get_rect(move=(3, 2))
|
|
|
|
def test_get_rect__invalid_kwarg_format(self):
|
|
"""Ensures get_rect detects invalid kwarg formats."""
|
|
mask = pygame.mask.Mask((3, 11))
|
|
|
|
with self.assertRaises(TypeError):
|
|
rect = mask.get_rect(right="1") # Wrong type.
|
|
|
|
with self.assertRaises(TypeError):
|
|
rect = mask.get_rect(bottom=(1,)) # Wrong type.
|
|
|
|
with self.assertRaises(TypeError):
|
|
rect = mask.get_rect(centerx=(1, 1)) # Wrong type.
|
|
|
|
with self.assertRaises(TypeError):
|
|
rect = mask.get_rect(midleft=(1, "1")) # Wrong type.
|
|
|
|
with self.assertRaises(TypeError):
|
|
rect = mask.get_rect(topright=(1,)) # Too few.
|
|
|
|
with self.assertRaises(TypeError):
|
|
rect = mask.get_rect(bottomleft=(1, 2, 3)) # Too many.
|
|
|
|
with self.assertRaises(TypeError):
|
|
rect = mask.get_rect(midbottom=1) # Wrong type.
|
|
|
|
def test_get_at(self):
|
|
"""Ensure individual mask bits are correctly retrieved."""
|
|
width, height = 5, 7
|
|
mask0 = pygame.mask.Mask((width, height))
|
|
mask1 = pygame.mask.Mask((width, height), fill=True)
|
|
mask0_expected_bit = 0
|
|
mask1_expected_bit = 1
|
|
pos = (width - 1, height - 1)
|
|
|
|
# Check twice to make sure bits aren't toggled.
|
|
self.assertEqual(mask0.get_at(pos), mask0_expected_bit)
|
|
self.assertEqual(mask0.get_at(pos=pos), mask0_expected_bit)
|
|
self.assertEqual(mask1.get_at(Vector2(pos)), mask1_expected_bit)
|
|
self.assertEqual(mask1.get_at(pos=Vector2(pos)), mask1_expected_bit)
|
|
|
|
def test_get_at__out_of_bounds(self):
|
|
"""Ensure get_at() checks bounds."""
|
|
width, height = 11, 3
|
|
mask = pygame.mask.Mask((width, height))
|
|
|
|
with self.assertRaises(IndexError):
|
|
mask.get_at((width, 0))
|
|
|
|
with self.assertRaises(IndexError):
|
|
mask.get_at((0, height))
|
|
|
|
with self.assertRaises(IndexError):
|
|
mask.get_at((-1, 0))
|
|
|
|
with self.assertRaises(IndexError):
|
|
mask.get_at((0, -1))
|
|
|
|
def test_set_at(self):
|
|
"""Ensure individual mask bits are set to 1."""
|
|
width, height = 13, 17
|
|
mask0 = pygame.mask.Mask((width, height))
|
|
mask1 = pygame.mask.Mask((width, height), fill=True)
|
|
mask0_expected_count = 1
|
|
mask1_expected_count = mask1.count()
|
|
expected_bit = 1
|
|
pos = (width - 1, height - 1)
|
|
|
|
mask0.set_at(pos, expected_bit) # set 0 to 1
|
|
mask1.set_at(pos=Vector2(pos), value=expected_bit) # set 1 to 1
|
|
|
|
self.assertEqual(mask0.get_at(pos), expected_bit)
|
|
self.assertEqual(mask0.count(), mask0_expected_count)
|
|
self.assertEqual(mask1.get_at(pos), expected_bit)
|
|
self.assertEqual(mask1.count(), mask1_expected_count)
|
|
|
|
def test_set_at__to_0(self):
|
|
"""Ensure individual mask bits are set to 0."""
|
|
width, height = 11, 7
|
|
mask0 = pygame.mask.Mask((width, height))
|
|
mask1 = pygame.mask.Mask((width, height), fill=True)
|
|
mask0_expected_count = 0
|
|
mask1_expected_count = mask1.count() - 1
|
|
expected_bit = 0
|
|
pos = (width - 1, height - 1)
|
|
|
|
mask0.set_at(pos, expected_bit) # set 0 to 0
|
|
mask1.set_at(pos, expected_bit) # set 1 to 0
|
|
|
|
self.assertEqual(mask0.get_at(pos), expected_bit)
|
|
self.assertEqual(mask0.count(), mask0_expected_count)
|
|
self.assertEqual(mask1.get_at(pos), expected_bit)
|
|
self.assertEqual(mask1.count(), mask1_expected_count)
|
|
|
|
def test_set_at__default_value(self):
|
|
"""Ensure individual mask bits are set using the default value."""
|
|
width, height = 3, 21
|
|
mask0 = pygame.mask.Mask((width, height))
|
|
mask1 = pygame.mask.Mask((width, height), fill=True)
|
|
mask0_expected_count = 1
|
|
mask1_expected_count = mask1.count()
|
|
expected_bit = 1
|
|
pos = (width - 1, height - 1)
|
|
|
|
mask0.set_at(pos) # set 0 to 1
|
|
mask1.set_at(pos) # set 1 to 1
|
|
|
|
self.assertEqual(mask0.get_at(pos), expected_bit)
|
|
self.assertEqual(mask0.count(), mask0_expected_count)
|
|
self.assertEqual(mask1.get_at(pos), expected_bit)
|
|
self.assertEqual(mask1.count(), mask1_expected_count)
|
|
|
|
def test_set_at__out_of_bounds(self):
|
|
"""Ensure set_at() checks bounds."""
|
|
width, height = 11, 3
|
|
mask = pygame.mask.Mask((width, height))
|
|
|
|
with self.assertRaises(IndexError):
|
|
mask.set_at((width, 0))
|
|
|
|
with self.assertRaises(IndexError):
|
|
mask.set_at((0, height))
|
|
|
|
with self.assertRaises(IndexError):
|
|
mask.set_at((-1, 0))
|
|
|
|
with self.assertRaises(IndexError):
|
|
mask.set_at((0, -1))
|
|
|
|
def test_overlap(self):
|
|
"""Ensure the overlap intersection is correctly calculated.
|
|
|
|
Testing the different combinations of full/empty masks:
|
|
(mask1-filled) 1 overlap 1 (mask2-filled)
|
|
(mask1-empty) 0 overlap 1 (mask2-filled)
|
|
(mask1-filled) 1 overlap 0 (mask2-empty)
|
|
(mask1-empty) 0 overlap 0 (mask2-empty)
|
|
"""
|
|
expected_size = (4, 4)
|
|
offset = (0, 0)
|
|
expected_default = None
|
|
expected_overlaps = {(True, True): offset}
|
|
|
|
for fill2 in (True, False):
|
|
mask2 = pygame.mask.Mask(expected_size, fill=fill2)
|
|
mask2_count = mask2.count()
|
|
|
|
for fill1 in (True, False):
|
|
key = (fill1, fill2)
|
|
msg = f"key={key}"
|
|
mask1 = pygame.mask.Mask(expected_size, fill=fill1)
|
|
mask1_count = mask1.count()
|
|
expected_pos = expected_overlaps.get(key, expected_default)
|
|
|
|
overlap_pos = mask1.overlap(mask2, offset)
|
|
|
|
self.assertEqual(overlap_pos, expected_pos, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), expected_size, msg)
|
|
self.assertEqual(mask2.get_size(), expected_size, msg)
|
|
|
|
def test_overlap__offset(self):
|
|
"""Ensure an offset overlap intersection is correctly calculated."""
|
|
mask1 = pygame.mask.Mask((65, 3), fill=True)
|
|
mask2 = pygame.mask.Mask((66, 4), fill=True)
|
|
mask1_count = mask1.count()
|
|
mask2_count = mask2.count()
|
|
mask1_size = mask1.get_size()
|
|
mask2_size = mask2.get_size()
|
|
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"offset={offset}"
|
|
expected_pos = (max(offset[0], 0), max(offset[1], 0))
|
|
|
|
overlap_pos = mask1.overlap(other=mask2, offset=offset)
|
|
|
|
self.assertEqual(overlap_pos, expected_pos, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask1_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
|
|
def test_overlap__offset_with_unset_bits(self):
|
|
"""Ensure an offset overlap intersection is correctly calculated
|
|
when (0, 0) bits not set."""
|
|
mask1 = pygame.mask.Mask((65, 3), fill=True)
|
|
mask2 = pygame.mask.Mask((66, 4), fill=True)
|
|
unset_pos = (0, 0)
|
|
mask1.set_at(unset_pos, 0)
|
|
mask2.set_at(unset_pos, 0)
|
|
mask1_count = mask1.count()
|
|
mask2_count = mask2.count()
|
|
mask1_size = mask1.get_size()
|
|
mask2_size = mask2.get_size()
|
|
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"offset={offset}"
|
|
x, y = offset
|
|
expected_y = max(y, 0)
|
|
if 0 == y:
|
|
expected_x = max(x + 1, 1)
|
|
elif 0 < y:
|
|
expected_x = max(x + 1, 0)
|
|
else:
|
|
expected_x = max(x, 1)
|
|
|
|
overlap_pos = mask1.overlap(mask2, Vector2(offset))
|
|
|
|
self.assertEqual(overlap_pos, (expected_x, expected_y), msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask1_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
self.assertEqual(mask1.get_at(unset_pos), 0, msg)
|
|
self.assertEqual(mask2.get_at(unset_pos), 0, msg)
|
|
|
|
def test_overlap__no_overlap(self):
|
|
"""Ensure an offset overlap intersection is correctly calculated
|
|
when there is no overlap."""
|
|
mask1 = pygame.mask.Mask((65, 3), fill=True)
|
|
mask1_count = mask1.count()
|
|
mask1_size = mask1.get_size()
|
|
|
|
mask2_w, mask2_h = 67, 5
|
|
mask2_size = (mask2_w, mask2_h)
|
|
mask2 = pygame.mask.Mask(mask2_size)
|
|
set_pos = (mask2_w - 1, mask2_h - 1)
|
|
mask2.set_at(set_pos)
|
|
mask2_count = 1
|
|
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"offset={offset}"
|
|
|
|
overlap_pos = mask1.overlap(mask2, offset)
|
|
|
|
self.assertIsNone(overlap_pos, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask1_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
self.assertEqual(mask2.get_at(set_pos), 1, msg)
|
|
|
|
def test_overlap__offset_boundary(self):
|
|
"""Ensures overlap handles offsets and boundaries correctly."""
|
|
mask1 = pygame.mask.Mask((13, 3), fill=True)
|
|
mask2 = pygame.mask.Mask((7, 5), fill=True)
|
|
mask1_count = mask1.count()
|
|
mask2_count = mask2.count()
|
|
mask1_size = mask1.get_size()
|
|
mask2_size = mask2.get_size()
|
|
|
|
# Check the 4 boundaries.
|
|
offsets = (
|
|
(mask1_size[0], 0), # off right
|
|
(0, mask1_size[1]), # off bottom
|
|
(-mask2_size[0], 0), # off left
|
|
(0, -mask2_size[1]),
|
|
) # off top
|
|
|
|
for offset in offsets:
|
|
msg = f"offset={offset}"
|
|
|
|
overlap_pos = mask1.overlap(mask2, offset)
|
|
|
|
self.assertIsNone(overlap_pos, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask1_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_overlap__bit_boundaries(self):
|
|
"""Ensures overlap handles masks of different sizes correctly.
|
|
|
|
Tests masks of different sizes, including:
|
|
-masks 31 to 33 bits wide (32 bit boundaries)
|
|
-masks 63 to 65 bits wide (64 bit boundaries)
|
|
"""
|
|
for height in range(2, 4):
|
|
for width in range(2, 66):
|
|
mask_size = (width, height)
|
|
mask_count = width * height
|
|
mask1 = pygame.mask.Mask(mask_size, fill=True)
|
|
mask2 = pygame.mask.Mask(mask_size, fill=True)
|
|
|
|
# Testing masks offset from each other.
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"size={mask_size}, offset={offset}"
|
|
expected_pos = (max(offset[0], 0), max(offset[1], 0))
|
|
|
|
overlap_pos = mask1.overlap(mask2, offset)
|
|
|
|
self.assertEqual(overlap_pos, expected_pos, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask_count, msg)
|
|
self.assertEqual(mask2.count(), mask_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask_size, msg)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_overlap__invalid_mask_arg(self):
|
|
"""Ensure overlap handles invalid mask arguments correctly."""
|
|
size = (5, 3)
|
|
offset = (0, 0)
|
|
mask = pygame.mask.Mask(size)
|
|
invalid_mask = pygame.Surface(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
overlap_pos = mask.overlap(invalid_mask, offset)
|
|
|
|
def test_overlap__invalid_offset_arg(self):
|
|
"""Ensure overlap handles invalid offset arguments correctly."""
|
|
size = (2, 7)
|
|
offset = "(0, 0)"
|
|
mask1 = pygame.mask.Mask(size)
|
|
mask2 = pygame.mask.Mask(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
overlap_pos = mask1.overlap(mask2, offset)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_overlap_area(self):
|
|
"""Ensure the overlap_area is correctly calculated.
|
|
|
|
Testing the different combinations of full/empty masks:
|
|
(mask1-filled) 1 overlap_area 1 (mask2-filled)
|
|
(mask1-empty) 0 overlap_area 1 (mask2-filled)
|
|
(mask1-filled) 1 overlap_area 0 (mask2-empty)
|
|
(mask1-empty) 0 overlap_area 0 (mask2-empty)
|
|
"""
|
|
expected_size = width, height = (4, 4)
|
|
offset = (0, 0)
|
|
expected_default = 0
|
|
expected_counts = {(True, True): width * height}
|
|
|
|
for fill2 in (True, False):
|
|
mask2 = pygame.mask.Mask(expected_size, fill=fill2)
|
|
mask2_count = mask2.count()
|
|
|
|
for fill1 in (True, False):
|
|
key = (fill1, fill2)
|
|
msg = f"key={key}"
|
|
mask1 = pygame.mask.Mask(expected_size, fill=fill1)
|
|
mask1_count = mask1.count()
|
|
expected_count = expected_counts.get(key, expected_default)
|
|
|
|
overlap_count = mask1.overlap_area(mask2, offset)
|
|
|
|
self.assertEqual(overlap_count, expected_count, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), expected_size, msg)
|
|
self.assertEqual(mask2.get_size(), expected_size, msg)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_overlap_area__offset(self):
|
|
"""Ensure an offset overlap_area is correctly calculated."""
|
|
mask1 = pygame.mask.Mask((65, 3), fill=True)
|
|
mask2 = pygame.mask.Mask((66, 4), fill=True)
|
|
mask1_count = mask1.count()
|
|
mask2_count = mask2.count()
|
|
mask1_size = mask1.get_size()
|
|
mask2_size = mask2.get_size()
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"offset={offset}"
|
|
rect2.topleft = offset
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_count = overlap_rect.w * overlap_rect.h
|
|
|
|
overlap_count = mask1.overlap_area(other=mask2, offset=offset)
|
|
|
|
self.assertEqual(overlap_count, expected_count, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask1_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
|
|
def test_overlap_area__offset_boundary(self):
|
|
"""Ensures overlap_area handles offsets and boundaries correctly."""
|
|
mask1 = pygame.mask.Mask((11, 3), fill=True)
|
|
mask2 = pygame.mask.Mask((5, 7), fill=True)
|
|
mask1_count = mask1.count()
|
|
mask2_count = mask2.count()
|
|
mask1_size = mask1.get_size()
|
|
mask2_size = mask2.get_size()
|
|
expected_count = 0
|
|
|
|
# Check the 4 boundaries.
|
|
offsets = (
|
|
(mask1_size[0], 0), # off right
|
|
(0, mask1_size[1]), # off bottom
|
|
(-mask2_size[0], 0), # off left
|
|
(0, -mask2_size[1]),
|
|
) # off top
|
|
|
|
for offset in offsets:
|
|
msg = f"offset={offset}"
|
|
|
|
overlap_count = mask1.overlap_area(mask2, Vector2(offset))
|
|
|
|
self.assertEqual(overlap_count, expected_count, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask1_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_overlap_area__bit_boundaries(self):
|
|
"""Ensures overlap_area handles masks of different sizes correctly.
|
|
|
|
Tests masks of different sizes, including:
|
|
-masks 31 to 33 bits wide (32 bit boundaries)
|
|
-masks 63 to 65 bits wide (64 bit boundaries)
|
|
"""
|
|
for height in range(2, 4):
|
|
for width in range(2, 66):
|
|
mask_size = (width, height)
|
|
mask_count = width * height
|
|
mask1 = pygame.mask.Mask(mask_size, fill=True)
|
|
mask2 = pygame.mask.Mask(mask_size, fill=True)
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
# Testing masks offset from each other.
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"size={mask_size}, offset={offset}"
|
|
rect2.topleft = offset
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_overlap_count = overlap_rect.w * overlap_rect.h
|
|
|
|
overlap_count = mask1.overlap_area(mask2, offset)
|
|
|
|
self.assertEqual(overlap_count, expected_overlap_count, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask_count, msg)
|
|
self.assertEqual(mask2.count(), mask_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask_size, msg)
|
|
|
|
def test_overlap_area__invalid_mask_arg(self):
|
|
"""Ensure overlap_area handles invalid mask arguments correctly."""
|
|
size = (3, 5)
|
|
offset = (0, 0)
|
|
mask = pygame.mask.Mask(size)
|
|
invalid_mask = pygame.Surface(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
overlap_count = mask.overlap_area(invalid_mask, offset)
|
|
|
|
def test_overlap_area__invalid_offset_arg(self):
|
|
"""Ensure overlap_area handles invalid offset arguments correctly."""
|
|
size = (7, 2)
|
|
offset = "(0, 0)"
|
|
mask1 = pygame.mask.Mask(size)
|
|
mask2 = pygame.mask.Mask(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
overlap_count = mask1.overlap_area(mask2, offset)
|
|
|
|
def test_overlap_mask(self):
|
|
"""Ensure overlap_mask's mask has correct bits set.
|
|
|
|
Testing the different combinations of full/empty masks:
|
|
(mask1-filled) 1 overlap_mask 1 (mask2-filled)
|
|
(mask1-empty) 0 overlap_mask 1 (mask2-filled)
|
|
(mask1-filled) 1 overlap_mask 0 (mask2-empty)
|
|
(mask1-empty) 0 overlap_mask 0 (mask2-empty)
|
|
"""
|
|
expected_size = (4, 4)
|
|
offset = (0, 0)
|
|
expected_default = pygame.mask.Mask(expected_size)
|
|
expected_masks = {(True, True): pygame.mask.Mask(expected_size, fill=True)}
|
|
|
|
for fill2 in (True, False):
|
|
mask2 = pygame.mask.Mask(expected_size, fill=fill2)
|
|
mask2_count = mask2.count()
|
|
|
|
for fill1 in (True, False):
|
|
key = (fill1, fill2)
|
|
msg = f"key={key}"
|
|
mask1 = pygame.mask.Mask(expected_size, fill=fill1)
|
|
mask1_count = mask1.count()
|
|
expected_mask = expected_masks.get(key, expected_default)
|
|
|
|
overlap_mask = mask1.overlap_mask(other=mask2, offset=offset)
|
|
|
|
self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg)
|
|
assertMaskEqual(self, overlap_mask, expected_mask, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), expected_size, msg)
|
|
self.assertEqual(mask2.get_size(), expected_size, msg)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_overlap_mask__bits_set(self):
|
|
"""Ensure overlap_mask's mask has correct bits set."""
|
|
mask1 = pygame.mask.Mask((50, 50), fill=True)
|
|
mask2 = pygame.mask.Mask((300, 10), fill=True)
|
|
mask1_count = mask1.count()
|
|
mask2_count = mask2.count()
|
|
mask1_size = mask1.get_size()
|
|
mask2_size = mask2.get_size()
|
|
|
|
mask3 = mask1.overlap_mask(mask2, (-1, 0))
|
|
|
|
for i in range(50):
|
|
for j in range(10):
|
|
self.assertEqual(mask3.get_at((i, j)), 1, f"({i}, {j})")
|
|
|
|
for i in range(50):
|
|
for j in range(11, 50):
|
|
self.assertEqual(mask3.get_at((i, j)), 0, f"({i}, {j})")
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count)
|
|
self.assertEqual(mask2.count(), mask2_count)
|
|
self.assertEqual(mask1.get_size(), mask1_size)
|
|
self.assertEqual(mask2.get_size(), mask2_size)
|
|
|
|
def test_overlap_mask__offset(self):
|
|
"""Ensure an offset overlap_mask's mask is correctly calculated."""
|
|
mask1 = pygame.mask.Mask((65, 3), fill=True)
|
|
mask2 = pygame.mask.Mask((66, 4), fill=True)
|
|
mask1_count = mask1.count()
|
|
mask2_count = mask2.count()
|
|
mask1_size = mask1.get_size()
|
|
mask2_size = mask2.get_size()
|
|
expected_mask = pygame.Mask(mask1_size)
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"offset={offset}"
|
|
rect2.topleft = offset
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_mask.clear()
|
|
expected_mask.draw(
|
|
pygame.Mask(overlap_rect.size, fill=True), overlap_rect.topleft
|
|
)
|
|
|
|
overlap_mask = mask1.overlap_mask(mask2, offset)
|
|
|
|
self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg)
|
|
assertMaskEqual(self, overlap_mask, expected_mask, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask1_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_overlap_mask__specific_offsets(self):
|
|
"""Ensure an offset overlap_mask's mask is correctly calculated.
|
|
|
|
Testing the specific case of:
|
|
-both masks are wider than 32 bits
|
|
-a positive offset is used
|
|
-the mask calling overlap_mask() is wider than the mask passed in
|
|
"""
|
|
mask1 = pygame.mask.Mask((65, 5), fill=True)
|
|
mask2 = pygame.mask.Mask((33, 3), fill=True)
|
|
expected_mask = pygame.Mask(mask1.get_size())
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
# This rect's corners are used to move rect2 around the inside of
|
|
# rect1.
|
|
corner_rect = rect1.inflate(-2, -2)
|
|
|
|
for corner in ("topleft", "topright", "bottomright", "bottomleft"):
|
|
setattr(rect2, corner, getattr(corner_rect, corner))
|
|
offset = rect2.topleft
|
|
msg = f"offset={offset}"
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_mask.clear()
|
|
expected_mask.draw(
|
|
pygame.Mask(overlap_rect.size, fill=True), overlap_rect.topleft
|
|
)
|
|
|
|
overlap_mask = mask1.overlap_mask(mask2, offset)
|
|
|
|
self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg)
|
|
assertMaskEqual(self, overlap_mask, expected_mask, msg)
|
|
|
|
def test_overlap_mask__offset_boundary(self):
|
|
"""Ensures overlap_mask handles offsets and boundaries correctly."""
|
|
mask1 = pygame.mask.Mask((9, 3), fill=True)
|
|
mask2 = pygame.mask.Mask((11, 5), fill=True)
|
|
mask1_count = mask1.count()
|
|
mask2_count = mask2.count()
|
|
mask1_size = mask1.get_size()
|
|
mask2_size = mask2.get_size()
|
|
expected_count = 0
|
|
expected_size = mask1_size
|
|
|
|
# Check the 4 boundaries.
|
|
offsets = (
|
|
(mask1_size[0], 0), # off right
|
|
(0, mask1_size[1]), # off bottom
|
|
(-mask2_size[0], 0), # off left
|
|
(0, -mask2_size[1]),
|
|
) # off top
|
|
|
|
for offset in offsets:
|
|
msg = f"offset={offset}"
|
|
|
|
overlap_mask = mask1.overlap_mask(mask2, offset)
|
|
|
|
self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(overlap_mask.count(), expected_count, msg)
|
|
self.assertEqual(overlap_mask.get_size(), expected_size, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask1_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_overlap_mask__bit_boundaries(self):
|
|
"""Ensures overlap_mask handles masks of different sizes correctly.
|
|
|
|
Tests masks of different sizes, including:
|
|
-masks 31 to 33 bits wide (32 bit boundaries)
|
|
-masks 63 to 65 bits wide (64 bit boundaries)
|
|
"""
|
|
for height in range(2, 4):
|
|
for width in range(2, 66):
|
|
mask_size = (width, height)
|
|
mask_count = width * height
|
|
mask1 = pygame.mask.Mask(mask_size, fill=True)
|
|
mask2 = pygame.mask.Mask(mask_size, fill=True)
|
|
expected_mask = pygame.Mask(mask_size)
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
# Testing masks offset from each other.
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"size={mask_size}, offset={offset}"
|
|
rect2.topleft = offset
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_mask.clear()
|
|
expected_mask.draw(
|
|
pygame.Mask(overlap_rect.size, fill=True), overlap_rect.topleft
|
|
)
|
|
|
|
overlap_mask = mask1.overlap_mask(mask2, offset)
|
|
|
|
self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg)
|
|
assertMaskEqual(self, overlap_mask, expected_mask, msg)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask_count, msg)
|
|
self.assertEqual(mask2.count(), mask_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask_size, msg)
|
|
|
|
def test_overlap_mask__invalid_mask_arg(self):
|
|
"""Ensure overlap_mask handles invalid mask arguments correctly."""
|
|
size = (3, 2)
|
|
offset = (0, 0)
|
|
mask = pygame.mask.Mask(size)
|
|
invalid_mask = pygame.Surface(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
overlap_mask = mask.overlap_mask(invalid_mask, offset)
|
|
|
|
def test_overlap_mask__invalid_offset_arg(self):
|
|
"""Ensure overlap_mask handles invalid offset arguments correctly."""
|
|
size = (5, 2)
|
|
offset = "(0, 0)"
|
|
mask1 = pygame.mask.Mask(size)
|
|
mask2 = pygame.mask.Mask(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
overlap_mask = mask1.overlap_mask(mask2, offset)
|
|
|
|
def test_mask_access(self):
|
|
"""do the set_at, and get_at parts work correctly?"""
|
|
m = pygame.Mask((10, 10))
|
|
m.set_at((0, 0), 1)
|
|
self.assertEqual(m.get_at((0, 0)), 1)
|
|
m.set_at((9, 0), 1)
|
|
self.assertEqual(m.get_at((9, 0)), 1)
|
|
|
|
# s = pygame.Surface((10,10))
|
|
# s.set_at((1,0), (0, 0, 1, 255))
|
|
# self.assertEqual(s.get_at((1,0)), (0, 0, 1, 255))
|
|
# s.set_at((-1,0), (0, 0, 1, 255))
|
|
|
|
# out of bounds, should get IndexError
|
|
self.assertRaises(IndexError, lambda: m.get_at((-1, 0)))
|
|
self.assertRaises(IndexError, lambda: m.set_at((-1, 0), 1))
|
|
self.assertRaises(IndexError, lambda: m.set_at((10, 0), 1))
|
|
self.assertRaises(IndexError, lambda: m.set_at((0, 10), 1))
|
|
|
|
def test_fill(self):
|
|
"""Ensure a mask can be filled."""
|
|
width, height = 11, 23
|
|
expected_count = width * height
|
|
expected_size = (width, height)
|
|
mask = pygame.mask.Mask(expected_size)
|
|
|
|
mask.fill()
|
|
|
|
self.assertEqual(mask.count(), expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_fill__bit_boundaries(self):
|
|
"""Ensures masks of different sizes are filled correctly.
|
|
|
|
Tests masks of different sizes, including:
|
|
-masks 31 to 33 bits wide (32 bit boundaries)
|
|
-masks 63 to 65 bits wide (64 bit boundaries)
|
|
"""
|
|
for height in range(1, 4):
|
|
for width in range(1, 66):
|
|
mask = pygame.mask.Mask((width, height))
|
|
expected_count = width * height
|
|
|
|
mask.fill()
|
|
|
|
self.assertEqual(
|
|
mask.count(), expected_count, f"size=({width}, {height})"
|
|
)
|
|
|
|
def test_clear(self):
|
|
"""Ensure a mask can be cleared."""
|
|
expected_count = 0
|
|
expected_size = (13, 27)
|
|
mask = pygame.mask.Mask(expected_size, fill=True)
|
|
|
|
mask.clear()
|
|
|
|
self.assertEqual(mask.count(), expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
def test_clear__bit_boundaries(self):
|
|
"""Ensures masks of different sizes are cleared correctly.
|
|
|
|
Tests masks of different sizes, including:
|
|
-masks 31 to 33 bits wide (32 bit boundaries)
|
|
-masks 63 to 65 bits wide (64 bit boundaries)
|
|
"""
|
|
expected_count = 0
|
|
|
|
for height in range(1, 4):
|
|
for width in range(1, 66):
|
|
mask = pygame.mask.Mask((width, height), fill=True)
|
|
|
|
mask.clear()
|
|
|
|
self.assertEqual(
|
|
mask.count(), expected_count, f"size=({width}, {height})"
|
|
)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_invert(self):
|
|
"""Ensure a mask can be inverted."""
|
|
side = 73
|
|
expected_size = (side, side)
|
|
mask1 = pygame.mask.Mask(expected_size)
|
|
mask2 = pygame.mask.Mask(expected_size, fill=True)
|
|
expected_count1 = side * side
|
|
expected_count2 = 0
|
|
|
|
for i in range(side):
|
|
expected_count1 -= 1
|
|
expected_count2 += 1
|
|
pos = (i, i)
|
|
mask1.set_at(pos)
|
|
mask2.set_at(pos, 0)
|
|
|
|
mask1.invert()
|
|
mask2.invert()
|
|
|
|
self.assertEqual(mask1.count(), expected_count1)
|
|
self.assertEqual(mask2.count(), expected_count2)
|
|
self.assertEqual(mask1.get_size(), expected_size)
|
|
self.assertEqual(mask2.get_size(), expected_size)
|
|
|
|
for i in range(side):
|
|
pos = (i, i)
|
|
msg = f"pos={pos}"
|
|
|
|
self.assertEqual(mask1.get_at(pos), 0, msg)
|
|
self.assertEqual(mask2.get_at(pos), 1, msg)
|
|
|
|
def test_invert__full(self):
|
|
"""Ensure a full mask can be inverted."""
|
|
expected_count = 0
|
|
expected_size = (43, 97)
|
|
mask = pygame.mask.Mask(expected_size, fill=True)
|
|
|
|
mask.invert()
|
|
|
|
self.assertEqual(mask.count(), expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
def test_invert__empty(self):
|
|
"""Ensure an empty mask can be inverted."""
|
|
width, height = 43, 97
|
|
expected_size = (width, height)
|
|
expected_count = width * height
|
|
mask = pygame.mask.Mask(expected_size)
|
|
|
|
mask.invert()
|
|
|
|
self.assertEqual(mask.count(), expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_invert__bit_boundaries(self):
|
|
"""Ensures masks of different sizes are inverted correctly.
|
|
|
|
Tests masks of different sizes, including:
|
|
-masks 31 to 33 bits wide (32 bit boundaries)
|
|
-masks 63 to 65 bits wide (64 bit boundaries)
|
|
"""
|
|
for fill in (True, False):
|
|
for height in range(1, 4):
|
|
for width in range(1, 66):
|
|
mask = pygame.mask.Mask((width, height), fill=fill)
|
|
expected_count = 0 if fill else width * height
|
|
|
|
mask.invert()
|
|
|
|
self.assertEqual(
|
|
mask.count(),
|
|
expected_count,
|
|
f"fill={fill}, size=({width}, {height})",
|
|
)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_scale(self):
|
|
"""Ensure a mask can be scaled."""
|
|
width, height = 43, 61
|
|
original_size = (width, height)
|
|
|
|
for fill in (True, False):
|
|
original_mask = pygame.mask.Mask(original_size, fill=fill)
|
|
original_count = width * height if fill else 0
|
|
|
|
# Test a range of sizes. Also tests scaling to 'same'
|
|
# size when new_w, new_h = width, height
|
|
for new_w in range(width - 10, width + 10):
|
|
for new_h in range(height - 10, height + 10):
|
|
expected_size = (new_w, new_h)
|
|
expected_count = new_w * new_h if fill else 0
|
|
msg = f"size={expected_size}"
|
|
|
|
mask = original_mask.scale(scale=expected_size)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.count(), expected_count, msg)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(original_mask.count(), original_count, msg)
|
|
self.assertEqual(original_mask.get_size(), original_size, msg)
|
|
|
|
def test_scale__negative_size(self):
|
|
"""Ensure scale handles negative sizes correctly."""
|
|
mask = pygame.Mask((100, 100))
|
|
|
|
with self.assertRaises(ValueError):
|
|
mask.scale((-1, -1))
|
|
|
|
with self.assertRaises(ValueError):
|
|
mask.scale(Vector2(-1, 10))
|
|
|
|
with self.assertRaises(ValueError):
|
|
mask.scale((10, -1))
|
|
|
|
def test_draw(self):
|
|
"""Ensure a mask can be drawn onto another mask.
|
|
|
|
Testing the different combinations of full/empty masks:
|
|
(mask1-filled) 1 draw 1 (mask2-filled)
|
|
(mask1-empty) 0 draw 1 (mask2-filled)
|
|
(mask1-filled) 1 draw 0 (mask2-empty)
|
|
(mask1-empty) 0 draw 0 (mask2-empty)
|
|
"""
|
|
expected_size = (4, 4)
|
|
offset = (0, 0)
|
|
expected_default = pygame.mask.Mask(expected_size, fill=True)
|
|
expected_masks = {(False, False): pygame.mask.Mask(expected_size)}
|
|
|
|
for fill2 in (True, False):
|
|
mask2 = pygame.mask.Mask(expected_size, fill=fill2)
|
|
mask2_count = mask2.count()
|
|
|
|
for fill1 in (True, False):
|
|
key = (fill1, fill2)
|
|
msg = f"key={key}"
|
|
mask1 = pygame.mask.Mask(expected_size, fill=fill1)
|
|
expected_mask = expected_masks.get(key, expected_default)
|
|
|
|
mask1.draw(mask2, offset)
|
|
|
|
assertMaskEqual(self, mask1, expected_mask, msg)
|
|
|
|
# Ensure mask2 unchanged.
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask2.get_size(), expected_size, msg)
|
|
|
|
def test_draw__offset(self):
|
|
"""Ensure an offset mask can be drawn onto another mask."""
|
|
mask1 = pygame.mask.Mask((65, 3))
|
|
mask2 = pygame.mask.Mask((66, 4), fill=True)
|
|
mask2_count = mask2.count()
|
|
mask2_size = mask2.get_size()
|
|
expected_mask = pygame.Mask(mask1.get_size())
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"offset={offset}"
|
|
rect2.topleft = offset
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_mask.clear()
|
|
|
|
# Normally draw() could be used to set these bits, but the draw()
|
|
# method is being tested here, so a loop is used instead.
|
|
for x in range(overlap_rect.left, overlap_rect.right):
|
|
for y in range(overlap_rect.top, overlap_rect.bottom):
|
|
expected_mask.set_at((x, y))
|
|
mask1.clear() # Ensure it's empty for testing each offset.
|
|
|
|
mask1.draw(other=mask2, offset=offset)
|
|
|
|
assertMaskEqual(self, mask1, expected_mask, msg)
|
|
|
|
# Ensure mask2 unchanged.
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
|
|
def test_draw__specific_offsets(self):
|
|
"""Ensure an offset mask can be drawn onto another mask.
|
|
|
|
Testing the specific case of:
|
|
-both masks are wider than 32 bits
|
|
-a positive offset is used
|
|
-the mask calling draw() is wider than the mask passed in
|
|
"""
|
|
mask1 = pygame.mask.Mask((65, 5))
|
|
mask2 = pygame.mask.Mask((33, 3), fill=True)
|
|
expected_mask = pygame.Mask(mask1.get_size())
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
# This rect's corners are used to move rect2 around the inside of
|
|
# rect1.
|
|
corner_rect = rect1.inflate(-2, -2)
|
|
|
|
for corner in ("topleft", "topright", "bottomright", "bottomleft"):
|
|
setattr(rect2, corner, getattr(corner_rect, corner))
|
|
offset = rect2.topleft
|
|
msg = f"offset={offset}"
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_mask.clear()
|
|
|
|
# Normally draw() could be used to set these bits, but the draw()
|
|
# method is being tested here, so a loop is used instead.
|
|
for x in range(overlap_rect.left, overlap_rect.right):
|
|
for y in range(overlap_rect.top, overlap_rect.bottom):
|
|
expected_mask.set_at((x, y))
|
|
mask1.clear() # Ensure it's empty for testing each offset.
|
|
|
|
mask1.draw(mask2, offset)
|
|
|
|
assertMaskEqual(self, mask1, expected_mask, msg)
|
|
|
|
def test_draw__offset_boundary(self):
|
|
"""Ensures draw handles offsets and boundaries correctly."""
|
|
mask1 = pygame.mask.Mask((13, 5))
|
|
mask2 = pygame.mask.Mask((7, 3), fill=True)
|
|
mask1_count = mask1.count()
|
|
mask2_count = mask2.count()
|
|
mask1_size = mask1.get_size()
|
|
mask2_size = mask2.get_size()
|
|
|
|
# Check the 4 boundaries.
|
|
offsets = (
|
|
(mask1_size[0], 0), # off right
|
|
(0, mask1_size[1]), # off bottom
|
|
(-mask2_size[0], 0), # off left
|
|
(0, -mask2_size[1]),
|
|
) # off top
|
|
|
|
for offset in offsets:
|
|
msg = f"offset={offset}"
|
|
|
|
mask1.draw(mask2, offset)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask1_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_draw__bit_boundaries(self):
|
|
"""Ensures draw handles masks of different sizes correctly.
|
|
|
|
Tests masks of different sizes, including:
|
|
-masks 31 to 33 bits wide (32 bit boundaries)
|
|
-masks 63 to 65 bits wide (64 bit boundaries)
|
|
"""
|
|
for height in range(2, 4):
|
|
for width in range(2, 66):
|
|
mask_size = (width, height)
|
|
mask_count = width * height
|
|
mask1 = pygame.mask.Mask(mask_size)
|
|
mask2 = pygame.mask.Mask(mask_size, fill=True)
|
|
expected_mask = pygame.Mask(mask_size)
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
# Testing masks offset from each other.
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"size={mask_size}, offset={offset}"
|
|
rect2.topleft = offset
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_mask.clear()
|
|
|
|
# Normally draw() could be used to set these bits, but the
|
|
# draw() method is being tested here, so a loop is used
|
|
# instead.
|
|
for x in range(overlap_rect.left, overlap_rect.right):
|
|
for y in range(overlap_rect.top, overlap_rect.bottom):
|
|
expected_mask.set_at((x, y))
|
|
mask1.clear() # Ensure it's empty for each test.
|
|
|
|
mask1.draw(mask2, offset)
|
|
|
|
assertMaskEqual(self, mask1, expected_mask, msg)
|
|
|
|
# Ensure mask2 unchanged.
|
|
self.assertEqual(mask2.count(), mask_count, msg)
|
|
self.assertEqual(mask2.get_size(), mask_size, msg)
|
|
|
|
def test_draw__invalid_mask_arg(self):
|
|
"""Ensure draw handles invalid mask arguments correctly."""
|
|
size = (7, 3)
|
|
offset = (0, 0)
|
|
mask = pygame.mask.Mask(size)
|
|
invalid_mask = pygame.Surface(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
mask.draw(invalid_mask, offset)
|
|
|
|
def test_draw__invalid_offset_arg(self):
|
|
"""Ensure draw handles invalid offset arguments correctly."""
|
|
size = (5, 7)
|
|
offset = "(0, 0)"
|
|
mask1 = pygame.mask.Mask(size)
|
|
mask2 = pygame.mask.Mask(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
mask1.draw(mask2, offset)
|
|
|
|
def test_erase(self):
|
|
"""Ensure a mask can erase another mask.
|
|
|
|
Testing the different combinations of full/empty masks:
|
|
(mask1-filled) 1 erase 1 (mask2-filled)
|
|
(mask1-empty) 0 erase 1 (mask2-filled)
|
|
(mask1-filled) 1 erase 0 (mask2-empty)
|
|
(mask1-empty) 0 erase 0 (mask2-empty)
|
|
"""
|
|
expected_size = (4, 4)
|
|
offset = (0, 0)
|
|
expected_default = pygame.mask.Mask(expected_size)
|
|
expected_masks = {(True, False): pygame.mask.Mask(expected_size, fill=True)}
|
|
|
|
for fill2 in (True, False):
|
|
mask2 = pygame.mask.Mask(expected_size, fill=fill2)
|
|
mask2_count = mask2.count()
|
|
|
|
for fill1 in (True, False):
|
|
key = (fill1, fill2)
|
|
msg = f"key={key}"
|
|
mask1 = pygame.mask.Mask(expected_size, fill=fill1)
|
|
expected_mask = expected_masks.get(key, expected_default)
|
|
|
|
mask1.erase(mask2, offset)
|
|
|
|
assertMaskEqual(self, mask1, expected_mask, msg)
|
|
|
|
# Ensure mask2 unchanged.
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask2.get_size(), expected_size, msg)
|
|
|
|
def test_erase__offset(self):
|
|
"""Ensure an offset mask can erase another mask."""
|
|
mask1 = pygame.mask.Mask((65, 3))
|
|
mask2 = pygame.mask.Mask((66, 4), fill=True)
|
|
mask2_count = mask2.count()
|
|
mask2_size = mask2.get_size()
|
|
expected_mask = pygame.Mask(mask1.get_size())
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"offset={offset}"
|
|
rect2.topleft = offset
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_mask.fill()
|
|
|
|
# Normally erase() could be used to clear these bits, but the
|
|
# erase() method is being tested here, so a loop is used instead.
|
|
for x in range(overlap_rect.left, overlap_rect.right):
|
|
for y in range(overlap_rect.top, overlap_rect.bottom):
|
|
expected_mask.set_at((x, y), 0)
|
|
mask1.fill() # Ensure it's filled for testing each offset.
|
|
|
|
mask1.erase(other=mask2, offset=offset)
|
|
|
|
assertMaskEqual(self, mask1, expected_mask, msg)
|
|
|
|
# Ensure mask2 unchanged.
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
|
|
def test_erase__specific_offsets(self):
|
|
"""Ensure an offset mask can erase another mask.
|
|
|
|
Testing the specific case of:
|
|
-both masks are wider than 32 bits
|
|
-a positive offset is used
|
|
-the mask calling erase() is wider than the mask passed in
|
|
"""
|
|
mask1 = pygame.mask.Mask((65, 5))
|
|
mask2 = pygame.mask.Mask((33, 3), fill=True)
|
|
expected_mask = pygame.Mask(mask1.get_size())
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
# This rect's corners are used to move rect2 around the inside of
|
|
# rect1.
|
|
corner_rect = rect1.inflate(-2, -2)
|
|
|
|
for corner in ("topleft", "topright", "bottomright", "bottomleft"):
|
|
setattr(rect2, corner, getattr(corner_rect, corner))
|
|
offset = rect2.topleft
|
|
msg = f"offset={offset}"
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_mask.fill()
|
|
|
|
# Normally erase() could be used to clear these bits, but the
|
|
# erase() method is being tested here, so a loop is used instead.
|
|
for x in range(overlap_rect.left, overlap_rect.right):
|
|
for y in range(overlap_rect.top, overlap_rect.bottom):
|
|
expected_mask.set_at((x, y), 0)
|
|
mask1.fill() # Ensure it's filled for testing each offset.
|
|
|
|
mask1.erase(mask2, Vector2(offset))
|
|
|
|
assertMaskEqual(self, mask1, expected_mask, msg)
|
|
|
|
def test_erase__offset_boundary(self):
|
|
"""Ensures erase handles offsets and boundaries correctly."""
|
|
mask1 = pygame.mask.Mask((7, 11), fill=True)
|
|
mask2 = pygame.mask.Mask((3, 13), fill=True)
|
|
mask1_count = mask1.count()
|
|
mask2_count = mask2.count()
|
|
mask1_size = mask1.get_size()
|
|
mask2_size = mask2.get_size()
|
|
|
|
# Check the 4 boundaries.
|
|
offsets = (
|
|
(mask1_size[0], 0), # off right
|
|
(0, mask1_size[1]), # off bottom
|
|
(-mask2_size[0], 0), # off left
|
|
(0, -mask2_size[1]),
|
|
) # off top
|
|
|
|
for offset in offsets:
|
|
msg = f"offset={offset}"
|
|
|
|
mask1.erase(mask2, offset)
|
|
|
|
# Ensure mask1/mask2 unchanged.
|
|
self.assertEqual(mask1.count(), mask1_count, msg)
|
|
self.assertEqual(mask2.count(), mask2_count, msg)
|
|
self.assertEqual(mask1.get_size(), mask1_size, msg)
|
|
self.assertEqual(mask2.get_size(), mask2_size, msg)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_erase__bit_boundaries(self):
|
|
"""Ensures erase handles masks of different sizes correctly.
|
|
|
|
Tests masks of different sizes, including:
|
|
-masks 31 to 33 bits wide (32 bit boundaries)
|
|
-masks 63 to 65 bits wide (64 bit boundaries)
|
|
"""
|
|
for height in range(2, 4):
|
|
for width in range(2, 66):
|
|
mask_size = (width, height)
|
|
mask_count = width * height
|
|
mask1 = pygame.mask.Mask(mask_size)
|
|
mask2 = pygame.mask.Mask(mask_size, fill=True)
|
|
expected_mask = pygame.Mask(mask_size)
|
|
|
|
# Using rects to help determine the overlapping area.
|
|
rect1 = mask1.get_rect()
|
|
rect2 = mask2.get_rect()
|
|
|
|
# Testing masks offset from each other.
|
|
for offset in self.ORIGIN_OFFSETS:
|
|
msg = f"size={mask_size}, offset={offset}"
|
|
rect2.topleft = offset
|
|
overlap_rect = rect1.clip(rect2)
|
|
expected_mask.fill()
|
|
|
|
# Normally erase() could be used to clear these bits, but
|
|
# the erase() method is being tested here, so a loop is
|
|
# used instead.
|
|
for x in range(overlap_rect.left, overlap_rect.right):
|
|
for y in range(overlap_rect.top, overlap_rect.bottom):
|
|
expected_mask.set_at((x, y), 0)
|
|
mask1.fill() # Ensure it's filled for each test.
|
|
|
|
mask1.erase(mask2, offset)
|
|
|
|
assertMaskEqual(self, mask1, expected_mask, msg)
|
|
|
|
# Ensure mask2 unchanged.
|
|
self.assertEqual(mask2.count(), mask_count, msg)
|
|
self.assertEqual(mask2.get_size(), mask_size, msg)
|
|
|
|
def test_erase__invalid_mask_arg(self):
|
|
"""Ensure erase handles invalid mask arguments correctly."""
|
|
size = (3, 7)
|
|
offset = (0, 0)
|
|
mask = pygame.mask.Mask(size)
|
|
invalid_mask = pygame.Surface(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
mask.erase(invalid_mask, offset)
|
|
|
|
def test_erase__invalid_offset_arg(self):
|
|
"""Ensure erase handles invalid offset arguments correctly."""
|
|
size = (7, 5)
|
|
offset = "(0, 0)"
|
|
mask1 = pygame.mask.Mask(size)
|
|
mask2 = pygame.mask.Mask(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
mask1.erase(mask2, offset)
|
|
|
|
def test_count(self):
|
|
"""Ensure a mask's set bits are correctly counted."""
|
|
side = 67
|
|
expected_size = (side, side)
|
|
expected_count = 0
|
|
mask = pygame.mask.Mask(expected_size)
|
|
|
|
for i in range(side):
|
|
expected_count += 1
|
|
mask.set_at((i, i))
|
|
|
|
count = mask.count()
|
|
|
|
self.assertEqual(count, expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_count__bit_boundaries(self):
|
|
"""Ensures the set bits of different sized masks are counted correctly.
|
|
|
|
Tests masks of different sizes, including:
|
|
-masks 31 to 33 bits wide (32 bit boundaries)
|
|
-masks 63 to 65 bits wide (64 bit boundaries)
|
|
"""
|
|
for fill in (True, False):
|
|
for height in range(1, 4):
|
|
for width in range(1, 66):
|
|
mask = pygame.mask.Mask((width, height), fill=fill)
|
|
expected_count = width * height if fill else 0
|
|
|
|
# Test toggling each bit.
|
|
for pos in ((x, y) for y in range(height) for x in range(width)):
|
|
if fill:
|
|
mask.set_at(pos, 0)
|
|
expected_count -= 1
|
|
else:
|
|
mask.set_at(pos, 1)
|
|
expected_count += 1
|
|
|
|
count = mask.count()
|
|
|
|
self.assertEqual(
|
|
count,
|
|
expected_count,
|
|
f"fill={fill}, size=({width}, {height}), pos={pos}",
|
|
)
|
|
|
|
def test_count__full_mask(self):
|
|
"""Ensure a full mask's set bits are correctly counted."""
|
|
width, height = 17, 97
|
|
expected_size = (width, height)
|
|
expected_count = width * height
|
|
mask = pygame.mask.Mask(expected_size, fill=True)
|
|
|
|
count = mask.count()
|
|
|
|
self.assertEqual(count, expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
def test_count__empty_mask(self):
|
|
"""Ensure an empty mask's set bits are correctly counted."""
|
|
expected_count = 0
|
|
expected_size = (13, 27)
|
|
mask = pygame.mask.Mask(expected_size)
|
|
|
|
count = mask.count()
|
|
|
|
self.assertEqual(count, expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
def test_centroid(self):
|
|
"""Ensure a filled mask's centroid is correctly calculated."""
|
|
mask = pygame.mask.Mask((5, 7), fill=True)
|
|
expected_centroid = mask.get_rect().center
|
|
|
|
centroid = mask.centroid()
|
|
|
|
self.assertEqual(centroid, expected_centroid)
|
|
|
|
def test_centroid__empty_mask(self):
|
|
"""Ensure an empty mask's centroid is correctly calculated."""
|
|
expected_centroid = (0, 0)
|
|
expected_size = (101, 103)
|
|
mask = pygame.mask.Mask(expected_size)
|
|
|
|
centroid = mask.centroid()
|
|
|
|
self.assertEqual(centroid, expected_centroid)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
def test_centroid__single_row(self):
|
|
"""Ensure a mask's centroid is correctly calculated
|
|
when setting points along a single row."""
|
|
width, height = (5, 7)
|
|
mask = pygame.mask.Mask((width, height))
|
|
|
|
for y in range(height):
|
|
mask.clear() # Clear for each row.
|
|
|
|
for x in range(width):
|
|
mask.set_at((x, y))
|
|
expected_centroid = (x // 2, y)
|
|
|
|
centroid = mask.centroid()
|
|
|
|
self.assertEqual(centroid, expected_centroid)
|
|
|
|
def test_centroid__two_rows(self):
|
|
"""Ensure a mask's centroid is correctly calculated
|
|
when setting points along two rows."""
|
|
width, height = (5, 7)
|
|
mask = pygame.mask.Mask((width, height))
|
|
|
|
# The first row is tested with each of the other rows.
|
|
for y in range(1, height):
|
|
mask.clear() # Clear for each set of rows.
|
|
|
|
for x in range(width):
|
|
mask.set_at((x, 0))
|
|
mask.set_at((x, y))
|
|
expected_centroid = (x // 2, y // 2)
|
|
|
|
centroid = mask.centroid()
|
|
|
|
self.assertEqual(centroid, expected_centroid)
|
|
|
|
def test_centroid__single_column(self):
|
|
"""Ensure a mask's centroid is correctly calculated
|
|
when setting points along a single column."""
|
|
width, height = (5, 7)
|
|
mask = pygame.mask.Mask((width, height))
|
|
|
|
for x in range(width):
|
|
mask.clear() # Clear for each column.
|
|
|
|
for y in range(height):
|
|
mask.set_at((x, y))
|
|
expected_centroid = (x, y // 2)
|
|
|
|
centroid = mask.centroid()
|
|
|
|
self.assertEqual(centroid, expected_centroid)
|
|
|
|
def test_centroid__two_columns(self):
|
|
"""Ensure a mask's centroid is correctly calculated
|
|
when setting points along two columns."""
|
|
width, height = (5, 7)
|
|
mask = pygame.mask.Mask((width, height))
|
|
|
|
# The first column is tested with each of the other columns.
|
|
for x in range(1, width):
|
|
mask.clear() # Clear for each set of columns.
|
|
|
|
for y in range(height):
|
|
mask.set_at((0, y))
|
|
mask.set_at((x, y))
|
|
expected_centroid = (x // 2, y // 2)
|
|
|
|
centroid = mask.centroid()
|
|
|
|
self.assertEqual(centroid, expected_centroid)
|
|
|
|
def test_centroid__all_corners(self):
|
|
"""Ensure a mask's centroid is correctly calculated
|
|
when its corners are set."""
|
|
mask = pygame.mask.Mask((5, 7))
|
|
expected_centroid = mask.get_rect().center
|
|
|
|
for corner in corners(mask):
|
|
mask.set_at(corner)
|
|
|
|
centroid = mask.centroid()
|
|
|
|
self.assertEqual(centroid, expected_centroid)
|
|
|
|
def test_centroid__two_corners(self):
|
|
"""Ensure a mask's centroid is correctly calculated
|
|
when only two corners are set."""
|
|
mask = pygame.mask.Mask((5, 7))
|
|
mask_rect = mask.get_rect()
|
|
mask_corners = corners(mask)
|
|
|
|
for i, corner1 in enumerate(mask_corners):
|
|
for corner2 in mask_corners[i + 1 :]:
|
|
mask.clear() # Clear for each pair of corners.
|
|
mask.set_at(corner1)
|
|
mask.set_at(corner2)
|
|
|
|
if corner1[0] == corner2[0]:
|
|
expected_centroid = (corner1[0], abs(corner1[1] - corner2[1]) // 2)
|
|
elif corner1[1] == corner2[1]:
|
|
expected_centroid = (abs(corner1[0] - corner2[0]) // 2, corner1[1])
|
|
else:
|
|
expected_centroid = mask_rect.center
|
|
|
|
centroid = mask.centroid()
|
|
|
|
self.assertEqual(centroid, expected_centroid)
|
|
|
|
def test_angle(self):
|
|
"""Ensure a mask's orientation angle is correctly calculated."""
|
|
expected_angle = -45.0
|
|
expected_size = (100, 100)
|
|
surface = pygame.Surface(expected_size)
|
|
mask = pygame.mask.from_surface(surface)
|
|
|
|
angle = mask.angle() # Returns the orientation of the pixels
|
|
|
|
self.assertIsInstance(angle, float)
|
|
self.assertEqual(angle, expected_angle)
|
|
|
|
def test_angle__empty_mask(self):
|
|
"""Ensure an empty mask's angle is correctly calculated."""
|
|
expected_angle = 0.0
|
|
expected_size = (107, 43)
|
|
mask = pygame.mask.Mask(expected_size)
|
|
|
|
angle = mask.angle()
|
|
|
|
self.assertIsInstance(angle, float)
|
|
self.assertAlmostEqual(angle, expected_angle)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
def test_drawing(self):
|
|
"""Test fill, clear, invert, draw, erase"""
|
|
m = pygame.Mask((100, 100))
|
|
self.assertEqual(m.count(), 0)
|
|
|
|
m.fill()
|
|
self.assertEqual(m.count(), 10000)
|
|
|
|
m2 = pygame.Mask((10, 10), fill=True)
|
|
m.erase(m2, (50, 50))
|
|
self.assertEqual(m.count(), 9900)
|
|
|
|
m.invert()
|
|
self.assertEqual(m.count(), 100)
|
|
|
|
m.draw(m2, (0, 0))
|
|
self.assertEqual(m.count(), 200)
|
|
|
|
m.clear()
|
|
self.assertEqual(m.count(), 0)
|
|
|
|
def test_outline(self):
|
|
""" """
|
|
|
|
m = pygame.Mask((20, 20))
|
|
self.assertEqual(m.outline(), [])
|
|
|
|
m.set_at((10, 10), 1)
|
|
self.assertEqual(m.outline(), [(10, 10)])
|
|
|
|
m.set_at((10, 12), 1)
|
|
self.assertEqual(m.outline(10), [(10, 10)])
|
|
|
|
m.set_at((11, 11), 1)
|
|
self.assertEqual(
|
|
m.outline(), [(10, 10), (11, 11), (10, 12), (11, 11), (10, 10)]
|
|
)
|
|
self.assertEqual(m.outline(every=2), [(10, 10), (10, 12), (10, 10)])
|
|
|
|
# TODO: Test more corner case outlines.
|
|
|
|
def test_convolve__size(self):
|
|
sizes = [(1, 1), (31, 31), (32, 32), (100, 100)]
|
|
for s1 in sizes:
|
|
m1 = pygame.Mask(s1)
|
|
for s2 in sizes:
|
|
m2 = pygame.Mask(s2)
|
|
o = m1.convolve(m2)
|
|
|
|
self.assertIsInstance(o, pygame.mask.Mask)
|
|
|
|
for i in (0, 1):
|
|
self.assertEqual(
|
|
o.get_size()[i], m1.get_size()[i] + m2.get_size()[i] - 1
|
|
)
|
|
|
|
def test_convolve__point_identities(self):
|
|
"""Convolving with a single point is the identity, while convolving a point with something flips it."""
|
|
m = random_mask((100, 100))
|
|
k = pygame.Mask((1, 1))
|
|
k.set_at((0, 0))
|
|
|
|
convolve_mask = m.convolve(k)
|
|
|
|
self.assertIsInstance(convolve_mask, pygame.mask.Mask)
|
|
assertMaskEqual(self, m, convolve_mask)
|
|
|
|
convolve_mask = k.convolve(k.convolve(m))
|
|
|
|
self.assertIsInstance(convolve_mask, pygame.mask.Mask)
|
|
assertMaskEqual(self, m, convolve_mask)
|
|
|
|
def test_convolve__with_output(self):
|
|
"""checks that convolution modifies only the correct portion of the output"""
|
|
|
|
m = random_mask((10, 10))
|
|
k = pygame.Mask((2, 2))
|
|
k.set_at((0, 0))
|
|
|
|
o = pygame.Mask((50, 50))
|
|
test = pygame.Mask((50, 50))
|
|
|
|
m.convolve(k, o)
|
|
test.draw(m, (1, 1))
|
|
|
|
self.assertIsInstance(o, pygame.mask.Mask)
|
|
assertMaskEqual(self, o, test)
|
|
|
|
o.clear()
|
|
test.clear()
|
|
|
|
m.convolve(other=k, output=o, offset=Vector2(10, 10))
|
|
test.draw(m, (11, 11))
|
|
|
|
self.assertIsInstance(o, pygame.mask.Mask)
|
|
assertMaskEqual(self, o, test)
|
|
|
|
def test_convolve__out_of_range(self):
|
|
full = pygame.Mask((2, 2), fill=True)
|
|
# Tuple of points (out of range) and the expected count for each.
|
|
pts_data = (((0, 3), 0), ((0, 2), 3), ((-2, -2), 1), ((-3, -3), 0))
|
|
|
|
for pt, expected_count in pts_data:
|
|
convolve_mask = full.convolve(full, None, pt)
|
|
|
|
self.assertIsInstance(convolve_mask, pygame.mask.Mask)
|
|
self.assertEqual(convolve_mask.count(), expected_count)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_convolve(self):
|
|
"""Tests the definition of convolution"""
|
|
m1 = random_mask((100, 100))
|
|
m2 = random_mask((100, 100))
|
|
conv = m1.convolve(m2)
|
|
|
|
self.assertIsInstance(conv, pygame.mask.Mask)
|
|
for i in range(conv.get_size()[0]):
|
|
for j in range(conv.get_size()[1]):
|
|
self.assertEqual(
|
|
conv.get_at((i, j)) == 0, m1.overlap(m2, (i - 99, j - 99)) is None
|
|
)
|
|
|
|
def _draw_component_pattern_box(self, mask, size, pos, inverse=False):
|
|
# Helper method to create/draw a 'box' pattern for testing.
|
|
#
|
|
# 111
|
|
# 101 3x3 example pattern
|
|
# 111
|
|
pattern = pygame.mask.Mask((size, size), fill=True)
|
|
pattern.set_at((size // 2, size // 2), 0)
|
|
|
|
if inverse:
|
|
mask.erase(pattern, pos)
|
|
pattern.invert()
|
|
else:
|
|
mask.draw(pattern, pos)
|
|
|
|
return pattern
|
|
|
|
def _draw_component_pattern_x(self, mask, size, pos, inverse=False):
|
|
# Helper method to create/draw an 'X' pattern for testing.
|
|
#
|
|
# 101
|
|
# 010 3x3 example pattern
|
|
# 101
|
|
pattern = pygame.mask.Mask((size, size))
|
|
|
|
ymax = size - 1
|
|
for y in range(size):
|
|
for x in range(size):
|
|
if x in [y, ymax - y]:
|
|
pattern.set_at((x, y))
|
|
|
|
if inverse:
|
|
mask.erase(pattern, pos)
|
|
pattern.invert()
|
|
else:
|
|
mask.draw(pattern, pos)
|
|
|
|
return pattern
|
|
|
|
def _draw_component_pattern_plus(self, mask, size, pos, inverse=False):
|
|
# Helper method to create/draw a '+' pattern for testing.
|
|
#
|
|
# 010
|
|
# 111 3x3 example pattern
|
|
# 010
|
|
pattern = pygame.mask.Mask((size, size))
|
|
|
|
xmid = ymid = size // 2
|
|
for y in range(size):
|
|
for x in range(size):
|
|
if x == xmid or y == ymid:
|
|
pattern.set_at((x, y))
|
|
|
|
if inverse:
|
|
mask.erase(pattern, pos)
|
|
pattern.invert()
|
|
else:
|
|
mask.draw(pattern, pos)
|
|
|
|
return pattern
|
|
|
|
def test_connected_component(self):
|
|
"""Ensure a mask's connected component is correctly calculated."""
|
|
width, height = 41, 27
|
|
expected_size = (width, height)
|
|
original_mask = pygame.mask.Mask(expected_size)
|
|
patterns = [] # Patterns and offsets.
|
|
|
|
# Draw some connected patterns on the original mask.
|
|
offset = (0, 0)
|
|
pattern = self._draw_component_pattern_x(original_mask, 3, offset)
|
|
patterns.append((pattern, offset))
|
|
|
|
size = 4
|
|
offset = (width - size, 0)
|
|
pattern = self._draw_component_pattern_plus(original_mask, size, offset)
|
|
patterns.append((pattern, offset))
|
|
|
|
# Make this one the largest connected component.
|
|
offset = (width // 2, height // 2)
|
|
pattern = self._draw_component_pattern_box(original_mask, 7, offset)
|
|
patterns.append((pattern, offset))
|
|
|
|
expected_pattern, expected_offset = patterns[-1]
|
|
expected_count = expected_pattern.count()
|
|
original_count = sum(p.count() for p, _ in patterns)
|
|
|
|
mask = original_mask.connected_component()
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask)
|
|
self.assertEqual(mask.count(), expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
self.assertEqual(
|
|
mask.overlap_area(expected_pattern, expected_offset), expected_count
|
|
)
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(original_mask.count(), original_count)
|
|
self.assertEqual(original_mask.get_size(), expected_size)
|
|
|
|
for pattern, offset in patterns:
|
|
self.assertEqual(
|
|
original_mask.overlap_area(pattern, offset), pattern.count()
|
|
)
|
|
|
|
def test_connected_component__full_mask(self):
|
|
"""Ensure a mask's connected component is correctly calculated
|
|
when the mask is full.
|
|
"""
|
|
expected_size = (23, 31)
|
|
original_mask = pygame.mask.Mask(expected_size, fill=True)
|
|
expected_count = original_mask.count()
|
|
|
|
mask = original_mask.connected_component()
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask)
|
|
self.assertEqual(mask.count(), expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(original_mask.count(), expected_count)
|
|
self.assertEqual(original_mask.get_size(), expected_size)
|
|
|
|
def test_connected_component__empty_mask(self):
|
|
"""Ensure a mask's connected component is correctly calculated
|
|
when the mask is empty.
|
|
"""
|
|
expected_size = (37, 43)
|
|
original_mask = pygame.mask.Mask(expected_size)
|
|
original_count = original_mask.count()
|
|
expected_count = 0
|
|
|
|
mask = original_mask.connected_component()
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask)
|
|
self.assertEqual(mask.count(), expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(original_mask.count(), original_count)
|
|
self.assertEqual(original_mask.get_size(), expected_size)
|
|
|
|
def test_connected_component__one_set_bit(self):
|
|
"""Ensure a mask's connected component is correctly calculated
|
|
when the coordinate's bit is set with a connected component of 1 bit.
|
|
"""
|
|
width, height = 71, 67
|
|
expected_size = (width, height)
|
|
original_mask = pygame.mask.Mask(expected_size, fill=True)
|
|
xset, yset = width // 2, height // 2
|
|
set_pos = (xset, yset)
|
|
expected_offset = (xset - 1, yset - 1)
|
|
|
|
# This isolates the bit at set_pos from all the other bits.
|
|
expected_pattern = self._draw_component_pattern_box(
|
|
original_mask, 3, expected_offset, inverse=True
|
|
)
|
|
expected_count = 1
|
|
original_count = original_mask.count()
|
|
|
|
mask = original_mask.connected_component(set_pos)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask)
|
|
self.assertEqual(mask.count(), expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
self.assertEqual(
|
|
mask.overlap_area(expected_pattern, expected_offset), expected_count
|
|
)
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(original_mask.count(), original_count)
|
|
self.assertEqual(original_mask.get_size(), expected_size)
|
|
self.assertEqual(
|
|
original_mask.overlap_area(expected_pattern, expected_offset),
|
|
expected_count,
|
|
)
|
|
|
|
def test_connected_component__multi_set_bits(self):
|
|
"""Ensure a mask's connected component is correctly calculated
|
|
when the coordinate's bit is set with a connected component of > 1 bit.
|
|
"""
|
|
expected_size = (113, 67)
|
|
original_mask = pygame.mask.Mask(expected_size)
|
|
p_width, p_height = 11, 13
|
|
set_pos = xset, yset = 11, 21
|
|
expected_offset = (xset - 1, yset - 1)
|
|
expected_pattern = pygame.mask.Mask((p_width, p_height), fill=True)
|
|
|
|
# Make an unsymmetrical pattern. All the set bits need to be connected
|
|
# in the resulting pattern for this to work properly.
|
|
for y in range(3, p_height):
|
|
for x in range(1, p_width):
|
|
if x in [y, y - 3, p_width - 4]:
|
|
expected_pattern.set_at((x, y), 0)
|
|
|
|
expected_count = expected_pattern.count()
|
|
original_mask.draw(expected_pattern, expected_offset)
|
|
|
|
mask = original_mask.connected_component(set_pos)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask)
|
|
self.assertEqual(mask.count(), expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
self.assertEqual(
|
|
mask.overlap_area(expected_pattern, expected_offset), expected_count
|
|
)
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(original_mask.count(), expected_count)
|
|
self.assertEqual(original_mask.get_size(), expected_size)
|
|
self.assertEqual(
|
|
original_mask.overlap_area(expected_pattern, expected_offset),
|
|
expected_count,
|
|
)
|
|
|
|
def test_connected_component__unset_bit(self):
|
|
"""Ensure a mask's connected component is correctly calculated
|
|
when the coordinate's bit is unset.
|
|
"""
|
|
width, height = 109, 101
|
|
expected_size = (width, height)
|
|
original_mask = pygame.mask.Mask(expected_size, fill=True)
|
|
unset_pos = (width // 2, height // 2)
|
|
original_mask.set_at(unset_pos, 0)
|
|
original_count = original_mask.count()
|
|
expected_count = 0
|
|
|
|
mask = original_mask.connected_component(unset_pos)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask)
|
|
self.assertEqual(mask.count(), expected_count)
|
|
self.assertEqual(mask.get_size(), expected_size)
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(original_mask.count(), original_count)
|
|
self.assertEqual(original_mask.get_size(), expected_size)
|
|
self.assertEqual(original_mask.get_at(unset_pos), 0)
|
|
|
|
def test_connected_component__out_of_bounds(self):
|
|
"""Ensure connected_component() checks bounds."""
|
|
width, height = 19, 11
|
|
original_size = (width, height)
|
|
original_mask = pygame.mask.Mask(original_size, fill=True)
|
|
original_count = original_mask.count()
|
|
|
|
for pos in ((0, -1), (-1, 0), (0, height + 1), (width + 1, 0)):
|
|
with self.assertRaises(IndexError):
|
|
mask = original_mask.connected_component(pos)
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(original_mask.count(), original_count)
|
|
self.assertEqual(original_mask.get_size(), original_size)
|
|
|
|
def test_connected_components(self):
|
|
""" """
|
|
m = pygame.Mask((10, 10))
|
|
|
|
self.assertListEqual(m.connected_components(), [])
|
|
|
|
comp = m.connected_component()
|
|
|
|
self.assertEqual(m.count(), comp.count())
|
|
|
|
m.set_at((0, 0), 1)
|
|
m.set_at((1, 1), 1)
|
|
comp = m.connected_component()
|
|
comps = m.connected_components()
|
|
comps1 = m.connected_components(1)
|
|
comps2 = m.connected_components(2)
|
|
comps3 = m.connected_components(3)
|
|
|
|
self.assertEqual(comp.count(), comps[0].count())
|
|
self.assertEqual(comps1[0].count(), 2)
|
|
self.assertEqual(comps2[0].count(), 2)
|
|
self.assertListEqual(comps3, [])
|
|
|
|
m.set_at((9, 9), 1)
|
|
comp = m.connected_component()
|
|
comp1 = m.connected_component((1, 1))
|
|
comp2 = m.connected_component((2, 2))
|
|
comps = m.connected_components()
|
|
comps1 = m.connected_components(1)
|
|
comps2 = m.connected_components(minimum=2)
|
|
comps3 = m.connected_components(3)
|
|
|
|
self.assertEqual(comp.count(), 2)
|
|
self.assertEqual(comp1.count(), 2)
|
|
self.assertEqual(comp2.count(), 0)
|
|
self.assertEqual(len(comps), 2)
|
|
self.assertEqual(len(comps1), 2)
|
|
self.assertEqual(len(comps2), 1)
|
|
self.assertEqual(len(comps3), 0)
|
|
|
|
for mask in comps:
|
|
self.assertIsInstance(mask, pygame.mask.Mask)
|
|
|
|
def test_connected_components__negative_min_with_empty_mask(self):
|
|
"""Ensures connected_components() properly handles negative min values
|
|
when the mask is empty.
|
|
|
|
Negative and zero values for the min parameter (minimum number of bits
|
|
per connected component) equate to setting it to one.
|
|
"""
|
|
expected_comps = []
|
|
mask_count = 0
|
|
mask_size = (65, 13)
|
|
mask = pygame.mask.Mask(mask_size)
|
|
|
|
connected_comps = mask.connected_components(-1)
|
|
|
|
self.assertListEqual(connected_comps, expected_comps)
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(mask.count(), mask_count)
|
|
self.assertEqual(mask.get_size(), mask_size)
|
|
|
|
def test_connected_components__negative_min_with_full_mask(self):
|
|
"""Ensures connected_components() properly handles negative min values
|
|
when the mask is full.
|
|
|
|
Negative and zero values for the min parameter (minimum number of bits
|
|
per connected component) equate to setting it to one.
|
|
"""
|
|
mask_size = (64, 11)
|
|
mask = pygame.mask.Mask(mask_size, fill=True)
|
|
mask_count = mask.count()
|
|
expected_len = 1
|
|
|
|
connected_comps = mask.connected_components(-2)
|
|
|
|
self.assertEqual(len(connected_comps), expected_len)
|
|
assertMaskEqual(self, connected_comps[0], mask)
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(mask.count(), mask_count)
|
|
self.assertEqual(mask.get_size(), mask_size)
|
|
|
|
def test_connected_components__negative_min_with_some_bits_set(self):
|
|
"""Ensures connected_components() properly handles negative min values
|
|
when the mask has some bits set.
|
|
|
|
Negative and zero values for the min parameter (minimum number of bits
|
|
per connected component) equate to setting it to one.
|
|
"""
|
|
mask_size = (64, 12)
|
|
mask = pygame.mask.Mask(mask_size)
|
|
expected_comps = {}
|
|
|
|
# Set the corners and the center positions. A new expected component
|
|
# mask is created for each point.
|
|
for corner in corners(mask):
|
|
mask.set_at(corner)
|
|
|
|
new_mask = pygame.mask.Mask(mask_size)
|
|
new_mask.set_at(corner)
|
|
expected_comps[corner] = new_mask
|
|
|
|
center = (mask_size[0] // 2, mask_size[1] // 2)
|
|
mask.set_at(center)
|
|
|
|
new_mask = pygame.mask.Mask(mask_size)
|
|
new_mask.set_at(center)
|
|
expected_comps[center] = new_mask
|
|
mask_count = mask.count()
|
|
|
|
connected_comps = mask.connected_components(-3)
|
|
|
|
self.assertEqual(len(connected_comps), len(expected_comps))
|
|
|
|
for comp in connected_comps:
|
|
# Since the masks in the connected component list can be in any
|
|
# order, loop the expected components to find its match.
|
|
found = False
|
|
|
|
for pt in tuple(expected_comps.keys()):
|
|
if comp.get_at(pt):
|
|
found = True
|
|
assertMaskEqual(self, comp, expected_comps[pt])
|
|
del expected_comps[pt] # Entry removed so it isn't reused.
|
|
break
|
|
|
|
self.assertTrue(found, f"missing component for pt={pt}")
|
|
|
|
# Ensure the original mask is unchanged.
|
|
self.assertEqual(mask.count(), mask_count)
|
|
self.assertEqual(mask.get_size(), mask_size)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_get_bounding_rects(self):
|
|
"""Ensures get_bounding_rects works correctly."""
|
|
# Create masks with different set point groups. Each group of
|
|
# connected set points will be contained in its own bounding rect.
|
|
# Diagonal points are considered connected.
|
|
mask_data = [] # [((size), ((rect1_pts), ...)), ...]
|
|
|
|
# Mask 1:
|
|
# |0123456789
|
|
# -+----------
|
|
# 0|1100000000
|
|
# 1|1000000000
|
|
# 2|0000000000
|
|
# 3|1001000000
|
|
# 4|0000000000
|
|
# 5|0000000000
|
|
# 6|0000000000
|
|
# 7|0000000000
|
|
# 8|0000000000
|
|
# 9|0000000000
|
|
mask_data.append(
|
|
(
|
|
(10, 10), # size
|
|
# Points to set for the 3 bounding rects.
|
|
(((0, 0), (1, 0), (0, 1)), ((0, 3),), ((3, 3),)), # rect1 # rect2
|
|
)
|
|
) # rect3
|
|
|
|
# Mask 2:
|
|
# |0123
|
|
# -+----
|
|
# 0|1100
|
|
# 1|1111
|
|
mask_data.append(
|
|
(
|
|
(4, 2), # size
|
|
# Points to set for the 1 bounding rect.
|
|
(((0, 0), (1, 0), (0, 1), (1, 1), (2, 1), (3, 1)),),
|
|
)
|
|
)
|
|
|
|
# Mask 3:
|
|
# |01234
|
|
# -+-----
|
|
# 0|00100
|
|
# 1|01110
|
|
# 2|00100
|
|
mask_data.append(
|
|
(
|
|
(5, 3), # size
|
|
# Points to set for the 1 bounding rect.
|
|
(((2, 0), (1, 1), (2, 1), (3, 1), (2, 2)),),
|
|
)
|
|
)
|
|
|
|
# Mask 4:
|
|
# |01234
|
|
# -+-----
|
|
# 0|00010
|
|
# 1|00100
|
|
# 2|01000
|
|
mask_data.append(
|
|
(
|
|
(5, 3), # size
|
|
# Points to set for the 1 bounding rect.
|
|
(((3, 0), (2, 1), (1, 2)),),
|
|
)
|
|
)
|
|
|
|
# Mask 5:
|
|
# |01234
|
|
# -+-----
|
|
# 0|00011
|
|
# 1|11111
|
|
mask_data.append(
|
|
(
|
|
(5, 2), # size
|
|
# Points to set for the 1 bounding rect.
|
|
(((3, 0), (4, 0), (0, 1), (1, 1), (2, 1), (3, 1)),),
|
|
)
|
|
)
|
|
|
|
# Mask 6:
|
|
# |01234
|
|
# -+-----
|
|
# 0|10001
|
|
# 1|00100
|
|
# 2|10001
|
|
mask_data.append(
|
|
(
|
|
(5, 3), # size
|
|
# Points to set for the 5 bounding rects.
|
|
(
|
|
((0, 0),), # rect1
|
|
((4, 0),), # rect2
|
|
((2, 1),), # rect3
|
|
((0, 2),), # rect4
|
|
((4, 2),),
|
|
),
|
|
)
|
|
) # rect5
|
|
|
|
for size, rect_point_tuples in mask_data:
|
|
rects = []
|
|
mask = pygame.Mask(size)
|
|
|
|
for rect_points in rect_point_tuples:
|
|
rects.append(create_bounding_rect(rect_points))
|
|
for pt in rect_points:
|
|
mask.set_at(pt)
|
|
|
|
expected_rects = sorted(rects, key=tuple)
|
|
|
|
rects = mask.get_bounding_rects()
|
|
|
|
self.assertListEqual(
|
|
sorted(mask.get_bounding_rects(), key=tuple),
|
|
expected_rects,
|
|
f"size={size}",
|
|
)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_to_surface(self):
|
|
"""Ensures empty and full masks can be drawn onto surfaces."""
|
|
expected_ref_count = 3
|
|
size = (33, 65)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
surface_color = pygame.Color("red")
|
|
test_fills = ((pygame.Color("white"), True), (pygame.Color("black"), False))
|
|
|
|
for expected_color, fill in test_fills:
|
|
surface.fill(surface_color)
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(surface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__create_surface(self):
|
|
"""Ensures empty and full masks can be drawn onto a created surface."""
|
|
expected_ref_count = 2
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
size = (33, 65)
|
|
test_fills = ((pygame.Color("white"), True), (pygame.Color("black"), False))
|
|
|
|
for expected_color, fill in test_fills:
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
|
|
for use_arg in (True, False):
|
|
if use_arg:
|
|
to_surface = mask.to_surface(None)
|
|
else:
|
|
to_surface = mask.to_surface()
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(to_surface.get_bitsize(), expected_depth)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__surface_param(self):
|
|
"""Ensures to_surface accepts a surface arg/kwarg."""
|
|
expected_ref_count = 4
|
|
expected_color = pygame.Color("white")
|
|
surface_color = pygame.Color("red")
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
surface = pygame.Surface(size)
|
|
kwargs = {"surface": surface}
|
|
|
|
for use_kwargs in (True, False):
|
|
surface.fill(surface_color)
|
|
|
|
if use_kwargs:
|
|
to_surface = mask.to_surface(**kwargs)
|
|
else:
|
|
to_surface = mask.to_surface(kwargs["surface"])
|
|
|
|
self.assertIs(to_surface, surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__setsurface_param(self):
|
|
"""Ensures to_surface accepts a setsurface arg/kwarg."""
|
|
expected_ref_count = 2
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
expected_color = pygame.Color("red")
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
setsurface = pygame.Surface(size, expected_flag, expected_depth)
|
|
setsurface.fill(expected_color)
|
|
kwargs = {"setsurface": setsurface}
|
|
|
|
for use_kwargs in (True, False):
|
|
if use_kwargs:
|
|
to_surface = mask.to_surface(**kwargs)
|
|
else:
|
|
to_surface = mask.to_surface(None, kwargs["setsurface"])
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(to_surface.get_bitsize(), expected_depth)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__unsetsurface_param(self):
|
|
"""Ensures to_surface accepts a unsetsurface arg/kwarg."""
|
|
expected_ref_count = 2
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
expected_color = pygame.Color("red")
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size)
|
|
unsetsurface = pygame.Surface(size, expected_flag, expected_depth)
|
|
unsetsurface.fill(expected_color)
|
|
kwargs = {"unsetsurface": unsetsurface}
|
|
|
|
for use_kwargs in (True, False):
|
|
if use_kwargs:
|
|
to_surface = mask.to_surface(**kwargs)
|
|
else:
|
|
to_surface = mask.to_surface(None, None, kwargs["unsetsurface"])
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(to_surface.get_bitsize(), expected_depth)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__setcolor_param(self):
|
|
"""Ensures to_surface accepts a setcolor arg/kwarg."""
|
|
expected_ref_count = 2
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
expected_color = pygame.Color("red")
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
kwargs = {"setcolor": expected_color}
|
|
|
|
for use_kwargs in (True, False):
|
|
if use_kwargs:
|
|
to_surface = mask.to_surface(**kwargs)
|
|
else:
|
|
to_surface = mask.to_surface(None, None, None, kwargs["setcolor"])
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(to_surface.get_bitsize(), expected_depth)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__setcolor_default(self):
|
|
"""Ensures the default setcolor is correct."""
|
|
expected_color = pygame.Color("white")
|
|
size = (3, 7)
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
|
|
to_surface = mask.to_surface(
|
|
surface=None, setsurface=None, unsetsurface=None, unsetcolor=None
|
|
)
|
|
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__unsetcolor_param(self):
|
|
"""Ensures to_surface accepts a unsetcolor arg/kwarg."""
|
|
expected_ref_count = 2
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
expected_color = pygame.Color("red")
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size)
|
|
kwargs = {"unsetcolor": expected_color}
|
|
|
|
for use_kwargs in (True, False):
|
|
if use_kwargs:
|
|
to_surface = mask.to_surface(**kwargs)
|
|
else:
|
|
to_surface = mask.to_surface(
|
|
None, None, None, None, kwargs["unsetcolor"]
|
|
)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(to_surface.get_bitsize(), expected_depth)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__unsetcolor_default(self):
|
|
"""Ensures the default unsetcolor is correct."""
|
|
expected_color = pygame.Color("black")
|
|
size = (3, 7)
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
to_surface = mask.to_surface(
|
|
surface=None, setsurface=None, unsetsurface=None, setcolor=None
|
|
)
|
|
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__dest_param(self):
|
|
"""Ensures to_surface accepts a dest arg/kwarg."""
|
|
expected_ref_count = 2
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
default_surface_color = (0, 0, 0, 0)
|
|
default_unsetcolor = pygame.Color("black")
|
|
dest = (0, 0)
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size)
|
|
kwargs = {"dest": dest}
|
|
|
|
for use_kwargs in (True, False):
|
|
if use_kwargs:
|
|
expected_color = default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(**kwargs)
|
|
else:
|
|
expected_color = default_surface_color
|
|
|
|
to_surface = mask.to_surface(
|
|
None, None, None, None, None, kwargs["dest"]
|
|
)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(to_surface.get_bitsize(), expected_depth)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__dest_default(self):
|
|
"""Ensures the default dest is correct."""
|
|
expected_color = pygame.Color("white")
|
|
surface_color = pygame.Color("red")
|
|
|
|
mask_size = (3, 2)
|
|
mask = pygame.mask.Mask(mask_size, fill=True)
|
|
mask_rect = mask.get_rect()
|
|
|
|
# Make the surface bigger than the mask.
|
|
surf_size = (mask_size[0] + 2, mask_size[1] + 1)
|
|
surface = pygame.Surface(surf_size, SRCALPHA, 32)
|
|
surface.fill(surface_color)
|
|
|
|
to_surface = mask.to_surface(
|
|
surface, setsurface=None, unsetsurface=None, unsetcolor=None
|
|
)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), surf_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect)
|
|
|
|
@unittest.expectedFailure
|
|
def test_to_surface__area_param(self):
|
|
"""Ensures to_surface accepts an area arg/kwarg."""
|
|
expected_ref_count = 2
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
default_surface_color = (0, 0, 0, 0)
|
|
default_unsetcolor = pygame.Color("black")
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size)
|
|
kwargs = {"area": mask.get_rect()}
|
|
|
|
for use_kwargs in (True, False):
|
|
if use_kwargs:
|
|
expected_color = default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(**kwargs)
|
|
else:
|
|
expected_color = default_surface_color
|
|
|
|
to_surface = mask.to_surface(
|
|
None, None, None, None, None, (0, 0), kwargs["area"]
|
|
)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(to_surface.get_bitsize(), expected_depth)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__area_default(self):
|
|
"""Ensures the default area is correct."""
|
|
expected_color = pygame.Color("white")
|
|
surface_color = pygame.Color("red")
|
|
|
|
mask_size = (3, 2)
|
|
mask = pygame.mask.Mask(mask_size, fill=True)
|
|
mask_rect = mask.get_rect()
|
|
|
|
# Make the surface bigger than the mask. The default area is the full
|
|
# area of the mask.
|
|
surf_size = (mask_size[0] + 2, mask_size[1] + 1)
|
|
surface = pygame.Surface(surf_size, SRCALPHA, 32)
|
|
surface.fill(surface_color)
|
|
|
|
to_surface = mask.to_surface(
|
|
surface, setsurface=None, unsetsurface=None, unsetcolor=None
|
|
)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), surf_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect)
|
|
|
|
def test_to_surface__kwargs(self):
|
|
"""Ensures to_surface accepts the correct kwargs."""
|
|
expected_color = pygame.Color("white")
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
surface = pygame.Surface(size)
|
|
surface_color = pygame.Color("red")
|
|
setsurface = surface.copy()
|
|
setsurface.fill(expected_color)
|
|
|
|
test_data = (
|
|
(None, None), # None entry allows loop to test all kwargs on first pass.
|
|
("dest", (0, 0)),
|
|
("unsetcolor", pygame.Color("yellow")),
|
|
("setcolor", expected_color),
|
|
("unsetsurface", surface.copy()),
|
|
("setsurface", setsurface),
|
|
("surface", surface),
|
|
)
|
|
|
|
kwargs = dict(test_data)
|
|
|
|
for name, _ in test_data:
|
|
kwargs.pop(name)
|
|
surface.fill(surface_color) # Clear for each test.
|
|
|
|
to_surface = mask.to_surface(**kwargs)
|
|
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__kwargs_create_surface(self):
|
|
"""Ensures to_surface accepts the correct kwargs
|
|
when creating a surface.
|
|
"""
|
|
expected_color = pygame.Color("black")
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size)
|
|
setsurface = pygame.Surface(size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface = setsurface.copy()
|
|
unsetsurface.fill(expected_color)
|
|
|
|
test_data = (
|
|
(None, None), # None entry allows loop to test all kwargs on first pass.
|
|
("dest", (0, 0)),
|
|
("unsetcolor", expected_color),
|
|
("setcolor", pygame.Color("yellow")),
|
|
("unsetsurface", unsetsurface),
|
|
("setsurface", setsurface),
|
|
("surface", None),
|
|
)
|
|
kwargs = dict(test_data)
|
|
|
|
for name, _ in test_data:
|
|
kwargs.pop(name)
|
|
|
|
to_surface = mask.to_surface(**kwargs)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__kwargs_order_independent(self):
|
|
"""Ensures to_surface kwargs are not order dependent."""
|
|
expected_color = pygame.Color("blue")
|
|
size = (3, 2)
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
surface = pygame.Surface(size)
|
|
|
|
to_surface = mask.to_surface(
|
|
dest=(0, 0),
|
|
setcolor=expected_color,
|
|
unsetcolor=None,
|
|
surface=surface,
|
|
unsetsurface=pygame.Surface(size),
|
|
setsurface=None,
|
|
)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__args_invalid_types(self):
|
|
"""Ensures to_surface detects invalid kwarg types."""
|
|
size = (3, 2)
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
invalid_surf = pygame.Color("green")
|
|
invalid_color = pygame.Surface(size)
|
|
|
|
with self.assertRaises(TypeError):
|
|
# Invalid dest.
|
|
mask.to_surface(None, None, None, None, None, (0,))
|
|
|
|
with self.assertRaises(TypeError):
|
|
# Invalid unsetcolor.
|
|
mask.to_surface(None, None, None, None, invalid_color)
|
|
|
|
with self.assertRaises(TypeError):
|
|
# Invalid setcolor.
|
|
mask.to_surface(None, None, None, invalid_color, None)
|
|
|
|
with self.assertRaises(TypeError):
|
|
# Invalid unsetsurface.
|
|
mask.to_surface(None, None, invalid_surf, None, None)
|
|
|
|
with self.assertRaises(TypeError):
|
|
# Invalid setsurface.
|
|
mask.to_surface(None, invalid_surf, None, None, None)
|
|
|
|
with self.assertRaises(TypeError):
|
|
# Invalid surface.
|
|
mask.to_surface(invalid_surf, None, None, None, None)
|
|
|
|
def test_to_surface__kwargs_invalid_types(self):
|
|
"""Ensures to_surface detects invalid kwarg types."""
|
|
size = (3, 2)
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
valid_kwargs = {
|
|
"surface": pygame.Surface(size),
|
|
"setsurface": pygame.Surface(size),
|
|
"unsetsurface": pygame.Surface(size),
|
|
"setcolor": pygame.Color("green"),
|
|
"unsetcolor": pygame.Color("green"),
|
|
"dest": (0, 0),
|
|
}
|
|
|
|
invalid_kwargs = {
|
|
"surface": (1, 2, 3, 4),
|
|
"setsurface": pygame.Color("green"),
|
|
"unsetsurface": ((1, 2), (2, 1)),
|
|
"setcolor": pygame.Mask((1, 2)),
|
|
"unsetcolor": pygame.Surface((2, 2)),
|
|
"dest": (0, 0, 0),
|
|
}
|
|
|
|
kwarg_order = (
|
|
"surface",
|
|
"setsurface",
|
|
"unsetsurface",
|
|
"setcolor",
|
|
"unsetcolor",
|
|
"dest",
|
|
)
|
|
|
|
for kwarg in kwarg_order:
|
|
kwargs = dict(valid_kwargs)
|
|
kwargs[kwarg] = invalid_kwargs[kwarg]
|
|
|
|
with self.assertRaises(TypeError):
|
|
mask.to_surface(**kwargs)
|
|
|
|
def test_to_surface__kwargs_invalid_name(self):
|
|
"""Ensures to_surface detects invalid kwarg names."""
|
|
mask = pygame.mask.Mask((3, 2))
|
|
kwargs = {"setcolour": pygame.Color("red")}
|
|
|
|
with self.assertRaises(TypeError):
|
|
mask.to_surface(**kwargs)
|
|
|
|
def test_to_surface__args_and_kwargs(self):
|
|
"""Ensures to_surface accepts a combination of args/kwargs"""
|
|
size = (5, 3)
|
|
|
|
surface_color = pygame.Color("red")
|
|
setsurface_color = pygame.Color("yellow")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
setcolor = pygame.Color("green")
|
|
unsetcolor = pygame.Color("cyan")
|
|
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
setsurface = surface.copy()
|
|
unsetsurface = surface.copy()
|
|
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
expected_color = setsurface_color
|
|
|
|
test_data = (
|
|
(None, None), # None entry allows loop to test all kwargs on first pass.
|
|
("surface", surface),
|
|
("setsurface", setsurface),
|
|
("unsetsurface", unsetsurface),
|
|
("setcolor", setcolor),
|
|
("unsetcolor", unsetcolor),
|
|
("dest", (0, 0)),
|
|
)
|
|
|
|
args = []
|
|
kwargs = dict(test_data)
|
|
|
|
# Loop gradually moves the kwargs to args.
|
|
for name, value in test_data:
|
|
if name is not None:
|
|
args.append(value)
|
|
kwargs.pop(name)
|
|
|
|
surface.fill(surface_color)
|
|
|
|
to_surface = mask.to_surface(*args, **kwargs)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__valid_setcolor_formats(self):
|
|
"""Ensures to_surface handles valid setcolor formats correctly."""
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
expected_color = pygame.Color("green")
|
|
test_colors = (
|
|
(0, 255, 0),
|
|
(0, 255, 0, 255),
|
|
surface.map_rgb(expected_color),
|
|
expected_color,
|
|
"green",
|
|
"#00FF00FF",
|
|
"0x00FF00FF",
|
|
)
|
|
|
|
for setcolor in test_colors:
|
|
to_surface = mask.to_surface(setcolor=setcolor)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__valid_unsetcolor_formats(self):
|
|
"""Ensures to_surface handles valid unsetcolor formats correctly."""
|
|
size = (5, 3)
|
|
mask = pygame.mask.Mask(size)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
expected_color = pygame.Color("green")
|
|
test_colors = (
|
|
(0, 255, 0),
|
|
(0, 255, 0, 255),
|
|
surface.map_rgb(expected_color),
|
|
expected_color,
|
|
"green",
|
|
"#00FF00FF",
|
|
"0x00FF00FF",
|
|
)
|
|
|
|
for unsetcolor in test_colors:
|
|
to_surface = mask.to_surface(unsetcolor=unsetcolor)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__invalid_setcolor_formats(self):
|
|
"""Ensures to_surface handles invalid setcolor formats correctly."""
|
|
mask = pygame.mask.Mask((5, 3))
|
|
|
|
for setcolor in ("green color", "#00FF00FF0", "0x00FF00FF0", (1, 2)):
|
|
with self.assertRaises(ValueError):
|
|
mask.to_surface(setcolor=setcolor)
|
|
|
|
for setcolor in (pygame.Surface((1, 2)), pygame.Mask((2, 1)), 1.1):
|
|
with self.assertRaises(TypeError):
|
|
mask.to_surface(setcolor=setcolor)
|
|
|
|
def test_to_surface__invalid_unsetcolor_formats(self):
|
|
"""Ensures to_surface handles invalid unsetcolor formats correctly."""
|
|
mask = pygame.mask.Mask((5, 3))
|
|
|
|
for unsetcolor in ("green color", "#00FF00FF0", "0x00FF00FF0", (1, 2)):
|
|
with self.assertRaises(ValueError):
|
|
mask.to_surface(unsetcolor=unsetcolor)
|
|
|
|
for unsetcolor in (pygame.Surface((1, 2)), pygame.Mask((2, 1)), 1.1):
|
|
with self.assertRaises(TypeError):
|
|
mask.to_surface(unsetcolor=unsetcolor)
|
|
|
|
def test_to_surface__valid_dest_formats(self):
|
|
"""Ensures to_surface handles valid dest formats correctly."""
|
|
expected_color = pygame.Color("white")
|
|
mask = pygame.mask.Mask((3, 5), fill=True)
|
|
dests = (
|
|
(0, 0),
|
|
[0, 0],
|
|
Vector2(0, 0),
|
|
(0, 0, 100, 100),
|
|
pygame.Rect((0, 0), (10, 10)),
|
|
)
|
|
|
|
for dest in dests:
|
|
to_surface = mask.to_surface(dest=dest)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__invalid_dest_formats(self):
|
|
"""Ensures to_surface handles invalid dest formats correctly."""
|
|
mask = pygame.mask.Mask((3, 5))
|
|
invalid_dests = (
|
|
(0,), # Incorrect size.
|
|
(0, 0, 0), # Incorrect size.
|
|
{0, 1}, # Incorrect type.
|
|
{0: 1}, # Incorrect type.
|
|
Rect,
|
|
) # Incorrect type.
|
|
|
|
for dest in invalid_dests:
|
|
with self.assertRaises(TypeError):
|
|
mask.to_surface(dest=dest)
|
|
|
|
def test_to_surface__negative_sized_dest_rect(self):
|
|
"""Ensures to_surface correctly handles negative sized dest rects."""
|
|
expected_color = pygame.Color("white")
|
|
mask = pygame.mask.Mask((3, 5), fill=True)
|
|
dests = (
|
|
pygame.Rect((0, 0), (10, -10)),
|
|
pygame.Rect((0, 0), (-10, 10)),
|
|
pygame.Rect((0, 0), (-10, -10)),
|
|
)
|
|
|
|
for dest in dests:
|
|
to_surface = mask.to_surface(dest=dest)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__zero_sized_dest_rect(self):
|
|
"""Ensures to_surface correctly handles zero sized dest rects."""
|
|
expected_color = pygame.Color("white")
|
|
mask = pygame.mask.Mask((3, 5), fill=True)
|
|
dests = (
|
|
pygame.Rect((0, 0), (0, 10)),
|
|
pygame.Rect((0, 0), (10, 0)),
|
|
pygame.Rect((0, 0), (0, 0)),
|
|
)
|
|
|
|
for dest in dests:
|
|
to_surface = mask.to_surface(dest=dest)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
@unittest.expectedFailure
|
|
def test_to_surface__valid_area_formats(self):
|
|
"""Ensures to_surface handles valid area formats correctly."""
|
|
size = (3, 5)
|
|
surface_color = pygame.Color("red")
|
|
expected_color = pygame.Color("white")
|
|
surface = pygame.Surface(size)
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
area_pos = (0, 0)
|
|
area_size = (2, 1)
|
|
areas = (
|
|
(area_pos[0], area_pos[1], area_size[0], area_size[1]),
|
|
(area_pos, area_size),
|
|
(area_pos, list(area_size)),
|
|
(list(area_pos), area_size),
|
|
(list(area_pos), list(area_size)),
|
|
[area_pos[0], area_pos[1], area_size[0], area_size[1]],
|
|
[area_pos, area_size],
|
|
[area_pos, list(area_size)],
|
|
[list(area_pos), area_size],
|
|
[list(area_pos), list(area_size)],
|
|
pygame.Rect(area_pos, area_size),
|
|
)
|
|
|
|
for area in areas:
|
|
surface.fill(surface_color)
|
|
area_rect = pygame.Rect(area)
|
|
|
|
to_surface = mask.to_surface(surface, area=area)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color, area_rect)
|
|
assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, area_rect)
|
|
|
|
@unittest.expectedFailure
|
|
def test_to_surface__invalid_area_formats(self):
|
|
"""Ensures to_surface handles invalid area formats correctly."""
|
|
mask = pygame.mask.Mask((3, 5))
|
|
invalid_areas = (
|
|
(0,), # Incorrect size.
|
|
(0, 0), # Incorrect size.
|
|
(0, 0, 1), # Incorrect size.
|
|
((0, 0), (1,)), # Incorrect size.
|
|
((0,), (1, 1)), # Incorrect size.
|
|
{0, 1, 2, 3}, # Incorrect type.
|
|
{0: 1, 2: 3}, # Incorrect type.
|
|
Rect, # Incorrect type.
|
|
)
|
|
|
|
for area in invalid_areas:
|
|
with self.assertRaisesRegex(TypeError, "invalid area argument"):
|
|
unused_to_surface = mask.to_surface(area=area)
|
|
|
|
@unittest.expectedFailure
|
|
def test_to_surface__negative_sized_area_rect(self):
|
|
"""Ensures to_surface correctly handles negative sized area rects."""
|
|
size = (3, 5)
|
|
surface_color = pygame.Color("red")
|
|
expected_color = pygame.Color("white")
|
|
surface = pygame.Surface(size)
|
|
mask = pygame.mask.Mask(size)
|
|
mask.set_at((0, 0))
|
|
|
|
# These rects should cause position (0, 0) of the mask to be drawn.
|
|
areas = (
|
|
pygame.Rect((0, 1), (1, -1)),
|
|
pygame.Rect((1, 0), (-1, 1)),
|
|
pygame.Rect((1, 1), (-1, -1)),
|
|
)
|
|
|
|
for area in areas:
|
|
surface.fill(surface_color)
|
|
|
|
to_surface = mask.to_surface(surface, area=area)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color, area)
|
|
assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, area)
|
|
|
|
@unittest.expectedFailure
|
|
def test_to_surface__zero_sized_area_rect(self):
|
|
"""Ensures to_surface correctly handles zero sized area rects."""
|
|
size = (3, 5)
|
|
expected_color = pygame.Color("red")
|
|
surface = pygame.Surface(size)
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
|
|
# Zero sized rect areas should cause none of the mask to be drawn.
|
|
areas = (
|
|
pygame.Rect((0, 0), (0, 1)),
|
|
pygame.Rect((0, 0), (1, 0)),
|
|
pygame.Rect((0, 0), (0, 0)),
|
|
)
|
|
|
|
for area in areas:
|
|
surface.fill(expected_color)
|
|
|
|
to_surface = mask.to_surface(surface, area=area)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__default_surface_with_param_combinations(self):
|
|
"""Ensures to_surface works with a default surface value
|
|
and combinations of other parameters.
|
|
|
|
This tests many different parameter combinations with full and empty
|
|
masks.
|
|
"""
|
|
expected_ref_count = 2
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
size = (5, 3)
|
|
dest = (0, 0)
|
|
|
|
default_surface_color = (0, 0, 0, 0)
|
|
setsurface_color = pygame.Color("yellow")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
setcolor = pygame.Color("green")
|
|
unsetcolor = pygame.Color("cyan")
|
|
|
|
setsurface = pygame.Surface(size, expected_flag, expected_depth)
|
|
unsetsurface = setsurface.copy()
|
|
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
kwargs = {
|
|
"setsurface": None,
|
|
"unsetsurface": None,
|
|
"setcolor": None,
|
|
"unsetcolor": None,
|
|
"dest": None,
|
|
}
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
|
|
# Test different combinations of parameters.
|
|
for setsurface_param in (setsurface, None):
|
|
kwargs["setsurface"] = setsurface_param
|
|
|
|
for unsetsurface_param in (unsetsurface, None):
|
|
kwargs["unsetsurface"] = unsetsurface_param
|
|
|
|
for setcolor_param in (setcolor, None):
|
|
kwargs["setcolor"] = setcolor_param
|
|
|
|
for unsetcolor_param in (unsetcolor, None):
|
|
kwargs["unsetcolor"] = unsetcolor_param
|
|
|
|
for dest_param in (dest, None):
|
|
if dest_param is None:
|
|
kwargs.pop("dest", None)
|
|
else:
|
|
kwargs["dest"] = dest_param
|
|
|
|
if fill:
|
|
if setsurface_param is not None:
|
|
expected_color = setsurface_color
|
|
elif setcolor_param is not None:
|
|
expected_color = setcolor
|
|
else:
|
|
expected_color = default_surface_color
|
|
else:
|
|
if unsetsurface_param is not None:
|
|
expected_color = unsetsurface_color
|
|
elif unsetcolor_param is not None:
|
|
expected_color = unsetcolor
|
|
else:
|
|
expected_color = default_surface_color
|
|
|
|
to_surface = mask.to_surface(**kwargs)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(
|
|
sys.getrefcount(to_surface), expected_ref_count
|
|
)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(
|
|
to_surface.get_bitsize(), expected_depth
|
|
)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__surface_with_param_combinations(self):
|
|
"""Ensures to_surface works with a surface value
|
|
and combinations of other parameters.
|
|
|
|
This tests many different parameter combinations with full and empty
|
|
masks.
|
|
"""
|
|
expected_ref_count = 4
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
size = (5, 3)
|
|
dest = (0, 0)
|
|
|
|
surface_color = pygame.Color("red")
|
|
setsurface_color = pygame.Color("yellow")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
setcolor = pygame.Color("green")
|
|
unsetcolor = pygame.Color("cyan")
|
|
|
|
surface = pygame.Surface(size, expected_flag, expected_depth)
|
|
setsurface = surface.copy()
|
|
unsetsurface = surface.copy()
|
|
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
kwargs = {
|
|
"surface": surface,
|
|
"setsurface": None,
|
|
"unsetsurface": None,
|
|
"setcolor": None,
|
|
"unsetcolor": None,
|
|
"dest": None,
|
|
}
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
|
|
# Test different combinations of parameters.
|
|
for setsurface_param in (setsurface, None):
|
|
kwargs["setsurface"] = setsurface_param
|
|
|
|
for unsetsurface_param in (unsetsurface, None):
|
|
kwargs["unsetsurface"] = unsetsurface_param
|
|
|
|
for setcolor_param in (setcolor, None):
|
|
kwargs["setcolor"] = setcolor_param
|
|
|
|
for unsetcolor_param in (unsetcolor, None):
|
|
kwargs["unsetcolor"] = unsetcolor_param
|
|
surface.fill(surface_color) # Clear for each test.
|
|
|
|
for dest_param in (dest, None):
|
|
if dest_param is None:
|
|
kwargs.pop("dest", None)
|
|
else:
|
|
kwargs["dest"] = dest_param
|
|
|
|
if fill:
|
|
if setsurface_param is not None:
|
|
expected_color = setsurface_color
|
|
elif setcolor_param is not None:
|
|
expected_color = setcolor
|
|
else:
|
|
expected_color = surface_color
|
|
else:
|
|
if unsetsurface_param is not None:
|
|
expected_color = unsetsurface_color
|
|
elif unsetcolor_param is not None:
|
|
expected_color = unsetcolor
|
|
else:
|
|
expected_color = surface_color
|
|
|
|
to_surface = mask.to_surface(**kwargs)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(
|
|
sys.getrefcount(to_surface), expected_ref_count
|
|
)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(
|
|
to_surface.get_bitsize(), expected_depth
|
|
)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__set_and_unset_bits(self):
|
|
"""Ensures that to_surface works correctly with with set/unset bits
|
|
when using the defaults for setcolor and unsetcolor.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
width, height = size = (10, 20)
|
|
mask = pygame.mask.Mask(size)
|
|
mask_rect = mask.get_rect()
|
|
|
|
surface = pygame.Surface(size)
|
|
surface_color = pygame.Color("red")
|
|
|
|
# Create a checkerboard pattern of set/unset bits.
|
|
for pos in ((x, y) for x in range(width) for y in range(x & 1, height, 2)):
|
|
mask.set_at(pos)
|
|
|
|
# Test different dest values.
|
|
for dest in self.ORIGIN_OFFSETS:
|
|
mask_rect.topleft = dest
|
|
surface.fill(surface_color)
|
|
|
|
to_surface = mask.to_surface(surface, dest=dest)
|
|
|
|
to_surface.lock() # Lock for possible speed up.
|
|
for pos in ((x, y) for x in range(width) for y in range(height)):
|
|
mask_pos = (pos[0] - dest[0], pos[1] - dest[1])
|
|
if not mask_rect.collidepoint(pos):
|
|
expected_color = surface_color
|
|
elif mask.get_at(mask_pos):
|
|
expected_color = default_setcolor
|
|
else:
|
|
expected_color = default_unsetcolor
|
|
|
|
self.assertEqual(to_surface.get_at(pos), expected_color, (dest, pos))
|
|
to_surface.unlock()
|
|
|
|
def test_to_surface__set_and_unset_bits_with_setsurface_unsetsurface(self):
|
|
"""Ensures that to_surface works correctly with with set/unset bits
|
|
when using setsurface and unsetsurface.
|
|
"""
|
|
width, height = size = (10, 20)
|
|
mask = pygame.mask.Mask(size)
|
|
mask_rect = mask.get_rect()
|
|
|
|
surface = pygame.Surface(size)
|
|
surface_color = pygame.Color("red")
|
|
|
|
setsurface = surface.copy()
|
|
setsurface_color = pygame.Color("green")
|
|
setsurface.fill(setsurface_color)
|
|
|
|
unsetsurface = surface.copy()
|
|
unsetsurface_color = pygame.Color("blue")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
# Create a checkerboard pattern of set/unset bits.
|
|
for pos in ((x, y) for x in range(width) for y in range(x & 1, height, 2)):
|
|
mask.set_at(pos)
|
|
|
|
# Test different dest values.
|
|
for dest in self.ORIGIN_OFFSETS:
|
|
mask_rect.topleft = dest
|
|
|
|
# Tests the color parameters set to None and also as their
|
|
# default values. Should have no effect as they are not being
|
|
# used, but this exercises different to_surface() code.
|
|
for disable_color_params in (True, False):
|
|
surface.fill(surface_color) # Clear for each test.
|
|
|
|
if disable_color_params:
|
|
to_surface = mask.to_surface(
|
|
surface,
|
|
dest=dest,
|
|
setsurface=setsurface,
|
|
unsetsurface=unsetsurface,
|
|
setcolor=None,
|
|
unsetcolor=None,
|
|
)
|
|
else:
|
|
to_surface = mask.to_surface(
|
|
surface,
|
|
dest=dest,
|
|
setsurface=setsurface,
|
|
unsetsurface=unsetsurface,
|
|
)
|
|
|
|
to_surface.lock() # Lock for possible speed up.
|
|
|
|
for pos in ((x, y) for x in range(width) for y in range(height)):
|
|
mask_pos = (pos[0] - dest[0], pos[1] - dest[1])
|
|
|
|
if not mask_rect.collidepoint(pos):
|
|
expected_color = surface_color
|
|
elif mask.get_at(mask_pos):
|
|
expected_color = setsurface_color
|
|
else:
|
|
expected_color = unsetsurface_color
|
|
|
|
self.assertEqual(to_surface.get_at(pos), expected_color)
|
|
to_surface.unlock()
|
|
|
|
def test_to_surface__surface_narrower_than_mask(self):
|
|
"""Ensures that surfaces narrower than the mask work correctly.
|
|
|
|
For this test the surface's width is less than the mask's width.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 20)
|
|
narrow_size = (6, 20)
|
|
|
|
surface = pygame.Surface(narrow_size)
|
|
surface_color = pygame.Color("red")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
surface.fill(surface_color) # Clear for each test.
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(surface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), narrow_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__setsurface_narrower_than_mask(self):
|
|
"""Ensures that setsurfaces narrower than the mask work correctly.
|
|
|
|
For this test the setsurface's width is less than the mask's width.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 20)
|
|
narrow_size = (6, 20)
|
|
|
|
setsurface = pygame.Surface(narrow_size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
setsurface_rect = setsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(setsurface=setsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_setcolor, setsurface_rect
|
|
)
|
|
else:
|
|
assertSurfaceFilled(self, to_surface, default_unsetcolor)
|
|
|
|
def test_to_surface__unsetsurface_narrower_than_mask(self):
|
|
"""Ensures that unsetsurfaces narrower than the mask work correctly.
|
|
|
|
For this test the unsetsurface's width is less than the mask's width.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 20)
|
|
narrow_size = (6, 20)
|
|
|
|
unsetsurface = pygame.Surface(narrow_size, SRCALPHA, 32)
|
|
unsetsurface_color = pygame.Color("red")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
unsetsurface_rect = unsetsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(unsetsurface=unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, default_setcolor)
|
|
else:
|
|
assertSurfaceFilled(
|
|
self, to_surface, unsetsurface_color, unsetsurface_rect
|
|
)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_unsetcolor, unsetsurface_rect
|
|
)
|
|
|
|
def test_to_surface__setsurface_narrower_than_mask_and_colors_none(self):
|
|
"""Ensures that setsurfaces narrower than the mask work correctly
|
|
when setcolor and unsetcolor are set to None.
|
|
|
|
For this test the setsurface's width is less than the mask's width.
|
|
"""
|
|
default_surface_color = (0, 0, 0, 0)
|
|
mask_size = (10, 20)
|
|
narrow_size = (6, 20)
|
|
|
|
setsurface = pygame.Surface(narrow_size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
setsurface_rect = setsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(
|
|
setsurface=setsurface, setcolor=None, unsetcolor=None
|
|
)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_surface_color, setsurface_rect
|
|
)
|
|
else:
|
|
assertSurfaceFilled(self, to_surface, default_surface_color)
|
|
|
|
def test_to_surface__unsetsurface_narrower_than_mask_and_colors_none(self):
|
|
"""Ensures that unsetsurfaces narrower than the mask work correctly
|
|
when setcolor and unsetcolor are set to None.
|
|
|
|
For this test the unsetsurface's width is less than the mask's width.
|
|
"""
|
|
default_surface_color = (0, 0, 0, 0)
|
|
mask_size = (10, 20)
|
|
narrow_size = (6, 20)
|
|
|
|
unsetsurface = pygame.Surface(narrow_size, SRCALPHA, 32)
|
|
unsetsurface_color = pygame.Color("red")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
unsetsurface_rect = unsetsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(
|
|
unsetsurface=unsetsurface, setcolor=None, unsetcolor=None
|
|
)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, default_surface_color)
|
|
else:
|
|
assertSurfaceFilled(
|
|
self, to_surface, unsetsurface_color, unsetsurface_rect
|
|
)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_surface_color, unsetsurface_rect
|
|
)
|
|
|
|
def test_to_surface__surface_wider_than_mask(self):
|
|
"""Ensures that surfaces wider than the mask work correctly.
|
|
|
|
For this test the surface's width is greater than the mask's width.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (6, 15)
|
|
wide_size = (11, 15)
|
|
|
|
surface = pygame.Surface(wide_size)
|
|
surface_color = pygame.Color("red")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
surface.fill(surface_color) # Clear for each test.
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(surface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), wide_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect)
|
|
|
|
def test_to_surface__setsurface_wider_than_mask(self):
|
|
"""Ensures that setsurfaces wider than the mask work correctly.
|
|
|
|
For this test the setsurface's width is greater than the mask's width.
|
|
"""
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (6, 15)
|
|
wide_size = (11, 15)
|
|
|
|
setsurface = pygame.Surface(wide_size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
expected_color = setsurface_color if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(setsurface=setsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__unsetsurface_wider_than_mask(self):
|
|
"""Ensures that unsetsurfaces wider than the mask work correctly.
|
|
|
|
For this test the unsetsurface's width is greater than the mask's
|
|
width.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
mask_size = (6, 15)
|
|
wide_size = (11, 15)
|
|
|
|
unsetsurface = pygame.Surface(wide_size, SRCALPHA, 32)
|
|
unsetsurface_color = pygame.Color("red")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
expected_color = default_setcolor if fill else unsetsurface_color
|
|
|
|
to_surface = mask.to_surface(unsetsurface=unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__surface_shorter_than_mask(self):
|
|
"""Ensures that surfaces shorter than the mask work correctly.
|
|
|
|
For this test the surface's height is less than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 11)
|
|
short_size = (10, 6)
|
|
|
|
surface = pygame.Surface(short_size)
|
|
surface_color = pygame.Color("red")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
surface.fill(surface_color) # Clear for each test.
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(surface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), short_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__setsurface_shorter_than_mask(self):
|
|
"""Ensures that setsurfaces shorter than the mask work correctly.
|
|
|
|
For this test the setsurface's height is less than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 11)
|
|
short_size = (10, 6)
|
|
|
|
setsurface = pygame.Surface(short_size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
setsurface_rect = setsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(setsurface=setsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_setcolor, setsurface_rect
|
|
)
|
|
else:
|
|
assertSurfaceFilled(self, to_surface, default_unsetcolor)
|
|
|
|
def test_to_surface__unsetsurface_shorter_than_mask(self):
|
|
"""Ensures that unsetsurfaces shorter than the mask work correctly.
|
|
|
|
For this test the unsetsurface's height is less than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 11)
|
|
short_size = (10, 6)
|
|
|
|
unsetsurface = pygame.Surface(short_size, SRCALPHA, 32)
|
|
unsetsurface_color = pygame.Color("red")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
unsetsurface_rect = unsetsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(unsetsurface=unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, default_setcolor)
|
|
else:
|
|
assertSurfaceFilled(
|
|
self, to_surface, unsetsurface_color, unsetsurface_rect
|
|
)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_unsetcolor, unsetsurface_rect
|
|
)
|
|
|
|
def test_to_surface__setsurface_shorter_than_mask_and_colors_none(self):
|
|
"""Ensures that setsurfaces shorter than the mask work correctly
|
|
when setcolor and unsetcolor are set to None.
|
|
|
|
For this test the setsurface's height is less than the mask's height.
|
|
"""
|
|
default_surface_color = (0, 0, 0, 0)
|
|
mask_size = (10, 11)
|
|
short_size = (10, 6)
|
|
|
|
setsurface = pygame.Surface(short_size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
setsurface_rect = setsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(
|
|
setsurface=setsurface, setcolor=None, unsetcolor=None
|
|
)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_surface_color, setsurface_rect
|
|
)
|
|
else:
|
|
assertSurfaceFilled(self, to_surface, default_surface_color)
|
|
|
|
def test_to_surface__unsetsurface_shorter_than_mask_and_colors_none(self):
|
|
"""Ensures that unsetsurfaces shorter than the mask work correctly
|
|
when setcolor and unsetcolor are set to None.
|
|
|
|
For this test the unsetsurface's height is less than the mask's height.
|
|
"""
|
|
default_surface_color = (0, 0, 0, 0)
|
|
mask_size = (10, 11)
|
|
short_size = (10, 6)
|
|
|
|
unsetsurface = pygame.Surface(short_size, SRCALPHA, 32)
|
|
unsetsurface_color = pygame.Color("red")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
unsetsurface_rect = unsetsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(
|
|
unsetsurface=unsetsurface, setcolor=None, unsetcolor=None
|
|
)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, default_surface_color)
|
|
else:
|
|
assertSurfaceFilled(
|
|
self, to_surface, unsetsurface_color, unsetsurface_rect
|
|
)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_surface_color, unsetsurface_rect
|
|
)
|
|
|
|
def test_to_surface__surface_taller_than_mask(self):
|
|
"""Ensures that surfaces taller than the mask work correctly.
|
|
|
|
For this test the surface's height is greater than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 6)
|
|
tall_size = (10, 11)
|
|
|
|
surface = pygame.Surface(tall_size)
|
|
surface_color = pygame.Color("red")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
surface.fill(surface_color) # Clear for each test.
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(surface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), tall_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect)
|
|
|
|
def test_to_surface__setsurface_taller_than_mask(self):
|
|
"""Ensures that setsurfaces taller than the mask work correctly.
|
|
|
|
For this test the setsurface's height is greater than the mask's
|
|
height.
|
|
"""
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 6)
|
|
tall_size = (10, 11)
|
|
|
|
setsurface = pygame.Surface(tall_size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
expected_color = setsurface_color if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(setsurface=setsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__unsetsurface_taller_than_mask(self):
|
|
"""Ensures that unsetsurfaces taller than the mask work correctly.
|
|
|
|
For this test the unsetsurface's height is greater than the mask's
|
|
height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
mask_size = (10, 6)
|
|
tall_size = (10, 11)
|
|
|
|
unsetsurface = pygame.Surface(tall_size, SRCALPHA, 32)
|
|
unsetsurface_color = pygame.Color("red")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
expected_color = default_setcolor if fill else unsetsurface_color
|
|
|
|
to_surface = mask.to_surface(unsetsurface=unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__surface_wider_and_taller_than_mask(self):
|
|
"""Ensures that surfaces wider and taller than the mask work correctly.
|
|
|
|
For this test the surface's width is greater than the mask's width and
|
|
the surface's height is greater than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (6, 8)
|
|
wide_tall_size = (11, 15)
|
|
|
|
surface = pygame.Surface(wide_tall_size)
|
|
surface_color = pygame.Color("red")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
surface.fill(surface_color) # Clear for each test.
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(surface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), wide_tall_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect)
|
|
|
|
def test_to_surface__setsurface_wider_and_taller_than_mask(self):
|
|
"""Ensures that setsurfaces wider and taller than the mask work
|
|
correctly.
|
|
|
|
For this test the setsurface's width is greater than the mask's width
|
|
and the setsurface's height is greater than the mask's height.
|
|
"""
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (6, 8)
|
|
wide_tall_size = (11, 15)
|
|
|
|
setsurface = pygame.Surface(wide_tall_size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
expected_color = setsurface_color if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(setsurface=setsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__unsetsurface_wider_and_taller_than_mask(self):
|
|
"""Ensures that unsetsurfaces wider and taller than the mask work
|
|
correctly.
|
|
|
|
For this test the unsetsurface's width is greater than the mask's width
|
|
and the unsetsurface's height is greater than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
mask_size = (6, 8)
|
|
wide_tall_size = (11, 15)
|
|
|
|
unsetsurface = pygame.Surface(wide_tall_size, SRCALPHA, 32)
|
|
unsetsurface_color = pygame.Color("red")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
expected_color = default_setcolor if fill else unsetsurface_color
|
|
|
|
to_surface = mask.to_surface(unsetsurface=unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__surface_wider_and_shorter_than_mask(self):
|
|
"""Ensures that surfaces wider and shorter than the mask work
|
|
correctly.
|
|
|
|
For this test the surface's width is greater than the mask's width and
|
|
the surface's height is less than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (7, 11)
|
|
wide_short_size = (13, 6)
|
|
|
|
surface = pygame.Surface(wide_short_size)
|
|
surface_color = pygame.Color("red")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
surface.fill(surface_color) # Clear for each test.
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(surface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), wide_short_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect)
|
|
|
|
def test_to_surface__setsurface_wider_and_shorter_than_mask(self):
|
|
"""Ensures that setsurfaces wider and shorter than the mask work
|
|
correctly.
|
|
|
|
For this test the setsurface's width is greater than the mask's width
|
|
and the setsurface's height is less than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (7, 11)
|
|
wide_short_size = (10, 6)
|
|
|
|
setsurface = pygame.Surface(wide_short_size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
setsurface_rect = setsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(setsurface=setsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_setcolor, setsurface_rect
|
|
)
|
|
else:
|
|
assertSurfaceFilled(self, to_surface, default_unsetcolor)
|
|
|
|
def test_to_surface__unsetsurface_wider_and_shorter_than_mask(self):
|
|
"""Ensures that unsetsurfaces wider and shorter than the mask work
|
|
correctly.
|
|
|
|
For this test the unsetsurface's width is greater than the mask's width
|
|
and the unsetsurface's height is less than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (7, 11)
|
|
wide_short_size = (10, 6)
|
|
|
|
unsetsurface = pygame.Surface(wide_short_size, SRCALPHA, 32)
|
|
unsetsurface_color = pygame.Color("red")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
unsetsurface_rect = unsetsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(unsetsurface=unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, default_setcolor)
|
|
else:
|
|
assertSurfaceFilled(
|
|
self, to_surface, unsetsurface_color, unsetsurface_rect
|
|
)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_unsetcolor, unsetsurface_rect
|
|
)
|
|
|
|
def test_to_surface__surface_narrower_and_taller_than_mask(self):
|
|
"""Ensures that surfaces narrower and taller than the mask work
|
|
correctly.
|
|
|
|
For this test the surface's width is less than the mask's width and
|
|
the surface's height is greater than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 8)
|
|
narrow_tall_size = (6, 15)
|
|
|
|
surface = pygame.Surface(narrow_tall_size)
|
|
surface_color = pygame.Color("red")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
surface.fill(surface_color) # Clear for each test.
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(surface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), narrow_tall_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect)
|
|
|
|
def test_to_surface__setsurface_narrower_and_taller_than_mask(self):
|
|
"""Ensures that setsurfaces narrower and taller than the mask work
|
|
correctly.
|
|
|
|
For this test the setsurface's width is less than the mask's width
|
|
and the setsurface's height is greater than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 8)
|
|
narrow_tall_size = (6, 15)
|
|
|
|
setsurface = pygame.Surface(narrow_tall_size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
setsurface_rect = setsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(setsurface=setsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_setcolor, setsurface_rect
|
|
)
|
|
else:
|
|
assertSurfaceFilled(self, to_surface, default_unsetcolor)
|
|
|
|
def test_to_surface__unsetsurface_narrower_and_taller_than_mask(self):
|
|
"""Ensures that unsetsurfaces narrower and taller than the mask work
|
|
correctly.
|
|
|
|
For this test the unsetsurface's width is less than the mask's width
|
|
and the unsetsurface's height is greater than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 8)
|
|
narrow_tall_size = (6, 15)
|
|
|
|
unsetsurface = pygame.Surface(narrow_tall_size, SRCALPHA, 32)
|
|
unsetsurface_color = pygame.Color("red")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
unsetsurface_rect = unsetsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(unsetsurface=unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, default_setcolor)
|
|
else:
|
|
assertSurfaceFilled(
|
|
self, to_surface, unsetsurface_color, unsetsurface_rect
|
|
)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_unsetcolor, unsetsurface_rect
|
|
)
|
|
|
|
def test_to_surface__surface_narrower_and_shorter_than_mask(self):
|
|
"""Ensures that surfaces narrower and shorter than the mask work
|
|
correctly.
|
|
|
|
For this test the surface's width is less than the mask's width and
|
|
the surface's height is less than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 18)
|
|
narrow_short_size = (6, 15)
|
|
|
|
surface = pygame.Surface(narrow_short_size)
|
|
surface_color = pygame.Color("red")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
surface.fill(surface_color) # Clear for each test.
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
to_surface = mask.to_surface(surface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), narrow_short_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect)
|
|
|
|
def test_to_surface__setsurface_narrower_and_shorter_than_mask(self):
|
|
"""Ensures that setsurfaces narrower and shorter than the mask work
|
|
correctly.
|
|
|
|
For this test the setsurface's width is less than the mask's width
|
|
and the setsurface's height is less than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 18)
|
|
narrow_short_size = (6, 15)
|
|
|
|
setsurface = pygame.Surface(narrow_short_size, SRCALPHA, 32)
|
|
setsurface_color = pygame.Color("red")
|
|
setsurface.fill(setsurface_color)
|
|
setsurface_rect = setsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(setsurface=setsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_setcolor, setsurface_rect
|
|
)
|
|
else:
|
|
assertSurfaceFilled(self, to_surface, default_unsetcolor)
|
|
|
|
def test_to_surface__unsetsurface_narrower_and_shorter_than_mask(self):
|
|
"""Ensures that unsetsurfaces narrower and shorter than the mask work
|
|
correctly.
|
|
|
|
For this test the unsetsurface's width is less than the mask's width
|
|
and the unsetsurface's height is less than the mask's height.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
mask_size = (10, 18)
|
|
narrow_short_size = (6, 15)
|
|
|
|
unsetsurface = pygame.Surface(narrow_short_size, SRCALPHA, 32)
|
|
unsetsurface_color = pygame.Color("red")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
unsetsurface_rect = unsetsurface.get_rect()
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(mask_size, fill=fill)
|
|
|
|
to_surface = mask.to_surface(unsetsurface=unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
# Different checks depending on if the mask was filled or not.
|
|
if fill:
|
|
assertSurfaceFilled(self, to_surface, default_setcolor)
|
|
else:
|
|
assertSurfaceFilled(
|
|
self, to_surface, unsetsurface_color, unsetsurface_rect
|
|
)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, default_unsetcolor, unsetsurface_rect
|
|
)
|
|
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_to_surface__all_surfaces_different_sizes_than_mask(self):
|
|
"""Ensures that all the surface parameters can be of different sizes."""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
surface_color = pygame.Color("red")
|
|
setsurface_color = pygame.Color("green")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
|
|
mask_size = (10, 15)
|
|
surface_size = (11, 14)
|
|
setsurface_size = (9, 8)
|
|
unsetsurface_size = (12, 16)
|
|
|
|
surface = pygame.Surface(surface_size)
|
|
setsurface = pygame.Surface(setsurface_size)
|
|
unsetsurface = pygame.Surface(unsetsurface_size)
|
|
|
|
surface.fill(surface_color)
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
surface_rect = surface.get_rect()
|
|
setsurface_rect = setsurface.get_rect()
|
|
unsetsurface_rect = unsetsurface.get_rect()
|
|
|
|
# Create a mask that is filled except for a rect in the center.
|
|
mask = pygame.mask.Mask(mask_size, fill=True)
|
|
mask_rect = mask.get_rect()
|
|
unfilled_rect = pygame.Rect((0, 0), (4, 5))
|
|
unfilled_rect.center = mask_rect.center
|
|
|
|
for pos in (
|
|
(x, y)
|
|
for x in range(unfilled_rect.x, unfilled_rect.w)
|
|
for y in range(unfilled_rect.y, unfilled_rect.h)
|
|
):
|
|
mask.set_at(pos, 0)
|
|
|
|
to_surface = mask.to_surface(surface, setsurface, unsetsurface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), surface_size)
|
|
|
|
# Check each surface pixel for the correct color.
|
|
to_surface.lock() # Lock for possible speed up.
|
|
|
|
for pos in (
|
|
(x, y) for x in range(surface_rect.w) for y in range(surface_rect.h)
|
|
):
|
|
if not mask_rect.collidepoint(pos):
|
|
expected_color = surface_color
|
|
elif mask.get_at(pos):
|
|
# Checking set bit colors.
|
|
if setsurface_rect.collidepoint(pos):
|
|
expected_color = setsurface_color
|
|
else:
|
|
expected_color = default_setcolor
|
|
else:
|
|
# Checking unset bit colors.
|
|
if unsetsurface_rect.collidepoint(pos):
|
|
expected_color = unsetsurface_color
|
|
else:
|
|
expected_color = default_unsetcolor
|
|
|
|
self.assertEqual(to_surface.get_at(pos), expected_color)
|
|
|
|
to_surface.unlock()
|
|
|
|
def test_to_surface__dest_locations(self):
|
|
"""Ensures dest values can be different locations on/off the surface."""
|
|
SIDE = 7
|
|
surface = pygame.Surface((SIDE, SIDE))
|
|
surface_rect = surface.get_rect()
|
|
dest_rect = surface_rect.copy()
|
|
|
|
surface_color = pygame.Color("red")
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
|
|
directions = (
|
|
((s, 0) for s in range(-SIDE, SIDE + 1)), # left to right
|
|
((0, s) for s in range(-SIDE, SIDE + 1)), # top to bottom
|
|
((s, s) for s in range(-SIDE, SIDE + 1)), # topleft to bottomright diag
|
|
((-s, s) for s in range(-SIDE, SIDE + 1)), # topright to bottomleft diag
|
|
)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask((SIDE, SIDE), fill=fill)
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
for direction in directions:
|
|
for pos in direction:
|
|
dest_rect.topleft = pos
|
|
overlap_rect = dest_rect.clip(surface_rect)
|
|
surface.fill(surface_color)
|
|
|
|
to_surface = mask.to_surface(surface, dest=dest_rect)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color, overlap_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, overlap_rect
|
|
)
|
|
|
|
@unittest.expectedFailure
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_to_surface__area_locations(self):
|
|
"""Ensures area rects can be different locations on/off the mask."""
|
|
SIDE = 7
|
|
surface = pygame.Surface((SIDE, SIDE))
|
|
|
|
surface_color = pygame.Color("red")
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
|
|
directions = (
|
|
((s, 0) for s in range(-SIDE, SIDE + 1)), # left to right
|
|
((0, s) for s in range(-SIDE, SIDE + 1)), # top to bottom
|
|
((s, s) for s in range(-SIDE, SIDE + 1)), # topleft to bottomright diag
|
|
((-s, s) for s in range(-SIDE, SIDE + 1)), # topright to bottomleft diag
|
|
)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask((SIDE, SIDE), fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
area_rect = mask_rect.copy()
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
for direction in directions:
|
|
for pos in direction:
|
|
area_rect.topleft = pos
|
|
overlap_rect = area_rect.clip(mask_rect)
|
|
overlap_rect.topleft = (0, 0)
|
|
surface.fill(surface_color)
|
|
|
|
to_surface = mask.to_surface(surface, area=area_rect)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color, overlap_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, overlap_rect
|
|
)
|
|
|
|
@unittest.expectedFailure
|
|
def test_to_surface__dest_and_area_locations(self):
|
|
"""Ensures dest/area values can be different locations on/off the
|
|
surface/mask.
|
|
"""
|
|
SIDE = 5
|
|
surface = pygame.Surface((SIDE, SIDE))
|
|
surface_rect = surface.get_rect()
|
|
dest_rect = surface_rect.copy()
|
|
|
|
surface_color = pygame.Color("red")
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
|
|
dest_directions = (
|
|
((s, 0) for s in range(-SIDE, SIDE + 1)), # left to right
|
|
((0, s) for s in range(-SIDE, SIDE + 1)), # top to bottom
|
|
((s, s) for s in range(-SIDE, SIDE + 1)), # topleft to bottomright diag
|
|
((-s, s) for s in range(-SIDE, SIDE + 1)), # topright to bottomleft diag
|
|
)
|
|
|
|
# Using only the topleft to bottomright diagonal to test the area (to
|
|
# reduce the number of loop iterations).
|
|
area_positions = list(dest_directions[2])
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask((SIDE, SIDE), fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
area_rect = mask_rect.copy()
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
for dest_direction in dest_directions:
|
|
for dest_pos in dest_direction:
|
|
dest_rect.topleft = dest_pos
|
|
|
|
for area_pos in area_positions:
|
|
area_rect.topleft = area_pos
|
|
area_overlap_rect = area_rect.clip(mask_rect)
|
|
area_overlap_rect.topleft = dest_rect.topleft
|
|
dest_overlap_rect = dest_rect.clip(area_overlap_rect)
|
|
|
|
surface.fill(surface_color)
|
|
|
|
to_surface = mask.to_surface(
|
|
surface, dest=dest_rect, area=area_rect
|
|
)
|
|
|
|
assertSurfaceFilled(
|
|
self, to_surface, expected_color, dest_overlap_rect
|
|
)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, dest_overlap_rect
|
|
)
|
|
|
|
@unittest.expectedFailure
|
|
def test_to_surface__area_sizes(self):
|
|
"""Ensures area rects can be different sizes."""
|
|
SIDE = 7
|
|
SIZES = (
|
|
(0, 0),
|
|
(0, 1),
|
|
(1, 0),
|
|
(1, 1),
|
|
(SIDE - 1, SIDE - 1),
|
|
(SIDE - 1, SIDE),
|
|
(SIDE, SIDE - 1),
|
|
(SIDE, SIDE),
|
|
(SIDE + 1, SIDE),
|
|
(SIDE, SIDE + 1),
|
|
(SIDE + 1, SIDE + 1),
|
|
)
|
|
|
|
surface = pygame.Surface((SIDE, SIDE))
|
|
surface_color = pygame.Color("red")
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask((SIDE, SIDE), fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
for size in SIZES:
|
|
area_rect = pygame.Rect((0, 0), size)
|
|
|
|
for pos in self.ORIGIN_OFFSETS:
|
|
area_rect.topleft = pos
|
|
overlap_rect = area_rect.clip(mask_rect)
|
|
overlap_rect.topleft = (0, 0)
|
|
surface.fill(surface_color)
|
|
|
|
to_surface = mask.to_surface(surface, area=area_rect)
|
|
|
|
assertSurfaceFilled(self, to_surface, expected_color, overlap_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, overlap_rect
|
|
)
|
|
|
|
def test_to_surface__surface_color_alphas(self):
|
|
"""Ensures the setsurface/unsetsurface color alpha values are respected."""
|
|
size = (13, 17)
|
|
setsurface_color = pygame.Color("green")
|
|
setsurface_color.a = 53
|
|
unsetsurface_color = pygame.Color("blue")
|
|
unsetsurface_color.a = 109
|
|
|
|
setsurface = pygame.Surface(size, flags=SRCALPHA, depth=32)
|
|
unsetsurface = pygame.Surface(size, flags=SRCALPHA, depth=32)
|
|
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
expected_color = setsurface_color if fill else unsetsurface_color
|
|
|
|
to_surface = mask.to_surface(
|
|
setsurface=setsurface, unsetsurface=unsetsurface
|
|
)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__color_alphas(self):
|
|
"""Ensures the setcolor/unsetcolor alpha values are respected."""
|
|
size = (13, 17)
|
|
setcolor = pygame.Color("green")
|
|
setcolor.a = 35
|
|
unsetcolor = pygame.Color("blue")
|
|
unsetcolor.a = 213
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
expected_color = setcolor if fill else unsetcolor
|
|
|
|
to_surface = mask.to_surface(setcolor=setcolor, unsetcolor=unsetcolor)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__depths(self):
|
|
"""Ensures to_surface works correctly with supported surface depths."""
|
|
size = (13, 17)
|
|
surface_color = pygame.Color("red")
|
|
setsurface_color = pygame.Color("green")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
|
|
for depth in (8, 16, 24, 32):
|
|
surface = pygame.Surface(size, depth=depth)
|
|
setsurface = pygame.Surface(size, depth=depth)
|
|
unsetsurface = pygame.Surface(size, depth=depth)
|
|
|
|
surface.fill(surface_color)
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
|
|
# For non-32 bit depths, the actual color can be different from
|
|
# what was filled.
|
|
expected_color = (
|
|
setsurface.get_at((0, 0)) if fill else unsetsurface.get_at((0, 0))
|
|
)
|
|
|
|
to_surface = mask.to_surface(surface, setsurface, unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__different_depths(self):
|
|
"""Ensures an exception is raised when surfaces have different depths."""
|
|
size = (13, 17)
|
|
surface_color = pygame.Color("red")
|
|
setsurface_color = pygame.Color("green")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
# Test different combinations of depths.
|
|
test_depths = (
|
|
(8, 8, 16), # surface/setsurface/unsetsurface
|
|
(8, 8, 24),
|
|
(8, 8, 32),
|
|
(16, 16, 24),
|
|
(16, 16, 32),
|
|
(24, 16, 8),
|
|
(32, 16, 16),
|
|
(32, 32, 16),
|
|
(32, 24, 32),
|
|
)
|
|
|
|
for depths in test_depths:
|
|
surface = pygame.Surface(size, depth=depths[0])
|
|
setsurface = pygame.Surface(size, depth=depths[1])
|
|
unsetsurface = pygame.Surface(size, depth=depths[2])
|
|
|
|
surface.fill(surface_color)
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
with self.assertRaises(ValueError):
|
|
mask.to_surface(surface, setsurface, unsetsurface)
|
|
|
|
def test_to_surface__different_depths_with_created_surfaces(self):
|
|
"""Ensures an exception is raised when surfaces have different depths
|
|
than the created surface.
|
|
"""
|
|
size = (13, 17)
|
|
setsurface_color = pygame.Color("green")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
# Test different combinations of depths. The created surface always has
|
|
# a depth of 32.
|
|
test_depths = (
|
|
(8, 8), # setsurface/unsetsurface
|
|
(16, 16),
|
|
(24, 24),
|
|
(24, 16),
|
|
(32, 8),
|
|
(32, 16),
|
|
(32, 24),
|
|
(16, 32),
|
|
)
|
|
|
|
for set_depth, unset_depth in test_depths:
|
|
setsurface = pygame.Surface(size, depth=set_depth)
|
|
unsetsurface = pygame.Surface(size, depth=unset_depth)
|
|
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
with self.assertRaises(ValueError):
|
|
mask.to_surface(setsurface=setsurface, unsetsurface=unsetsurface)
|
|
|
|
def test_to_surface__same_srcalphas(self):
|
|
"""Ensures to_surface works correctly when the SRCALPHA flag is set or not."""
|
|
size = (13, 17)
|
|
surface_color = pygame.Color("red")
|
|
setsurface_color = pygame.Color("green")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
|
|
for depth in (16, 32):
|
|
for flags in (0, SRCALPHA):
|
|
surface = pygame.Surface(size, flags=flags, depth=depth)
|
|
setsurface = pygame.Surface(size, flags=flags, depth=depth)
|
|
unsetsurface = pygame.Surface(size, flags=flags, depth=depth)
|
|
|
|
surface.fill(surface_color)
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
expected_color = setsurface_color if fill else unsetsurface_color
|
|
|
|
to_surface = mask.to_surface(surface, setsurface, unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
if flags:
|
|
self.assertTrue(to_surface.get_flags() & flags)
|
|
|
|
def test_to_surface__same_srcalphas_with_created_surfaces(self):
|
|
"""Ensures to_surface works correctly when it creates a surface
|
|
and the SRCALPHA flag is set on both setsurface and unsetsurface.
|
|
"""
|
|
size = (13, 17)
|
|
setsurface_color = pygame.Color("green")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
# The created surface always has a depth of 32 and the SRCALPHA flag set.
|
|
expected_flags = SRCALPHA
|
|
|
|
setsurface = pygame.Surface(size, flags=expected_flags, depth=32)
|
|
unsetsurface = pygame.Surface(size, flags=expected_flags, depth=32)
|
|
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
expected_color = setsurface_color if fill else unsetsurface_color
|
|
|
|
to_surface = mask.to_surface(
|
|
setsurface=setsurface, unsetsurface=unsetsurface
|
|
)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
self.assertTrue(to_surface.get_flags() & expected_flags)
|
|
|
|
def test_to_surface__different_srcalphas(self):
|
|
"""Ensures an exception is raised when surfaces have different SRCALPHA
|
|
flag settings.
|
|
"""
|
|
size = (13, 17)
|
|
surface_color = pygame.Color("red")
|
|
setsurface_color = pygame.Color("green")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
# Test different combinations of SRCALPHA flags.
|
|
test_flags = (
|
|
(SRCALPHA, 0, 0), # surface/setsurface/unsetsurface
|
|
(SRCALPHA, SRCALPHA, 0),
|
|
(0, SRCALPHA, SRCALPHA),
|
|
(0, 0, SRCALPHA),
|
|
)
|
|
|
|
for depth in (16, 32):
|
|
for flags in test_flags:
|
|
surface = pygame.Surface(size, flags=flags[0], depth=depth)
|
|
setsurface = pygame.Surface(size, flags=flags[1], depth=depth)
|
|
unsetsurface = pygame.Surface(size, flags=flags[2], depth=depth)
|
|
|
|
surface.fill(surface_color)
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
with self.assertRaises(ValueError):
|
|
mask.to_surface(surface, setsurface, unsetsurface)
|
|
|
|
def test_to_surface__different_srcalphas_with_created_surfaces(self):
|
|
"""Ensures an exception is raised when surfaces have different SRCALPHA
|
|
flag settings than the created surface.
|
|
"""
|
|
size = (13, 17)
|
|
setsurface_color = pygame.Color("green")
|
|
unsetsurface_color = pygame.Color("blue")
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
for depth in (16, 32):
|
|
# Test different combinations of SRCALPHA flags. The created
|
|
# surface always has the SRCALPHA flag set.
|
|
for flags in ((0, 0), (SRCALPHA, 0), (0, SRCALPHA)):
|
|
setsurface = pygame.Surface(size, flags=flags[0], depth=depth)
|
|
unsetsurface = pygame.Surface(size, flags=flags[1], depth=depth)
|
|
|
|
setsurface.fill(setsurface_color)
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
with self.assertRaises(ValueError):
|
|
mask.to_surface(setsurface=setsurface, unsetsurface=unsetsurface)
|
|
|
|
def test_to_surface__dest_on_surface(self):
|
|
"""Ensures dest values on the surface work correctly
|
|
when using the defaults for setcolor and unsetcolor.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
width, height = size = (5, 9)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
surface_color = pygame.Color("red")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
# Test the dest parameter at different locations on the surface.
|
|
for dest in ((x, y) for y in range(height) for x in range(width)):
|
|
surface.fill(surface_color) # Clear for each test.
|
|
mask_rect.topleft = dest
|
|
|
|
to_surface = mask.to_surface(surface, dest=dest)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, mask_rect
|
|
)
|
|
|
|
def test_to_surface__dest_on_surface_with_setsurface_unsetsurface(self):
|
|
"""Ensures dest values on the surface work correctly
|
|
when using setsurface and unsetsurface.
|
|
"""
|
|
width, height = size = (5, 9)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
surface_color = pygame.Color("red")
|
|
|
|
setsurface = surface.copy()
|
|
setsurface_color = pygame.Color("green")
|
|
setsurface.fill(setsurface_color)
|
|
|
|
unsetsurface = surface.copy()
|
|
unsetsurface_color = pygame.Color("blue")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
# Using different kwargs to exercise different to_surface() code.
|
|
# Should not have any impact on the resulting drawn surfaces.
|
|
kwargs = {
|
|
"surface": surface,
|
|
"setsurface": setsurface,
|
|
"unsetsurface": unsetsurface,
|
|
"dest": None,
|
|
}
|
|
|
|
color_kwargs = dict(kwargs)
|
|
color_kwargs.update((("setcolor", None), ("unsetcolor", None)))
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
expected_color = setsurface_color if fill else unsetsurface_color
|
|
|
|
# Test the dest parameter at different locations on the surface.
|
|
for dest in ((x, y) for y in range(height) for x in range(width)):
|
|
mask_rect.topleft = dest
|
|
|
|
for use_color_params in (True, False):
|
|
surface.fill(surface_color) # Clear for each test.
|
|
|
|
test_kwargs = color_kwargs if use_color_params else kwargs
|
|
test_kwargs["dest"] = dest
|
|
to_surface = mask.to_surface(**test_kwargs)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, mask_rect
|
|
)
|
|
|
|
def test_to_surface__dest_off_surface(self):
|
|
"""Ensures dest values off the surface work correctly
|
|
when using the defaults for setcolor and unsetcolor.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
width, height = size = (5, 7)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
surface_color = pygame.Color("red")
|
|
|
|
# Test different dests off the surface.
|
|
dests = [(-width, -height), (-width, 0), (0, -height)]
|
|
dests.extend(off_corners(surface.get_rect()))
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
for dest in dests:
|
|
surface.fill(surface_color) # Clear for each test.
|
|
mask_rect.topleft = dest
|
|
|
|
to_surface = mask.to_surface(surface, dest=dest)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, mask_rect
|
|
)
|
|
|
|
def test_to_surface__dest_off_surface_with_setsurface_unsetsurface(self):
|
|
"""Ensures dest values off the surface work correctly
|
|
when using setsurface and unsetsurface.
|
|
"""
|
|
width, height = size = (5, 7)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
surface_color = pygame.Color("red")
|
|
|
|
setsurface = surface.copy()
|
|
setsurface_color = pygame.Color("green")
|
|
setsurface.fill(setsurface_color)
|
|
|
|
unsetsurface = surface.copy()
|
|
unsetsurface_color = pygame.Color("blue")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
# Test different dests off the surface.
|
|
dests = [(-width, -height), (-width, 0), (0, -height)]
|
|
dests.extend(off_corners(surface.get_rect()))
|
|
|
|
# Using different kwargs to exercise different to_surface() code.
|
|
# Should not have any impact on the resulting drawn surfaces.
|
|
kwargs = {
|
|
"surface": surface,
|
|
"setsurface": setsurface,
|
|
"unsetsurface": unsetsurface,
|
|
"dest": None,
|
|
}
|
|
|
|
color_kwargs = dict(kwargs)
|
|
color_kwargs.update((("setcolor", None), ("unsetcolor", None)))
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
expected_color = setsurface_color if fill else unsetsurface_color
|
|
|
|
for dest in dests:
|
|
mask_rect.topleft = dest
|
|
|
|
for use_color_params in (True, False):
|
|
surface.fill(surface_color) # Clear for each test.
|
|
test_kwargs = color_kwargs if use_color_params else kwargs
|
|
test_kwargs["dest"] = dest
|
|
to_surface = mask.to_surface(**test_kwargs)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, mask_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, mask_rect
|
|
)
|
|
|
|
@unittest.expectedFailure
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_to_surface__area_on_mask(self):
|
|
"""Ensures area values on the mask work correctly
|
|
when using the defaults for setcolor and unsetcolor.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
width, height = size = (5, 9)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
surface_color = pygame.Color("red")
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
area_rect = mask_rect.copy()
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
# Testing the area parameter at different locations on the mask.
|
|
for pos in ((x, y) for y in range(height) for x in range(width)):
|
|
surface.fill(surface_color) # Clear for each test.
|
|
area_rect.topleft = pos
|
|
overlap_rect = mask_rect.clip(area_rect)
|
|
overlap_rect.topleft = (0, 0)
|
|
|
|
to_surface = mask.to_surface(surface, area=area_rect)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, overlap_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, overlap_rect
|
|
)
|
|
|
|
@unittest.expectedFailure
|
|
def test_to_surface__area_on_mask_with_setsurface_unsetsurface(self):
|
|
"""Ensures area values on the mask work correctly
|
|
when using setsurface and unsetsurface.
|
|
"""
|
|
width, height = size = (5, 9)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
surface_color = pygame.Color("red")
|
|
|
|
setsurface = surface.copy()
|
|
setsurface_color = pygame.Color("green")
|
|
setsurface.fill(setsurface_color)
|
|
|
|
unsetsurface = surface.copy()
|
|
unsetsurface_color = pygame.Color("blue")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
# Using the values in kwargs vs color_kwargs tests different to_surface
|
|
# code. Should not have any impact on the resulting drawn surfaces.
|
|
kwargs = {
|
|
"surface": surface,
|
|
"setsurface": setsurface,
|
|
"unsetsurface": unsetsurface,
|
|
"area": pygame.Rect((0, 0), size),
|
|
}
|
|
|
|
color_kwargs = dict(kwargs)
|
|
color_kwargs.update((("setcolor", None), ("unsetcolor", None)))
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
area_rect = mask_rect.copy()
|
|
expected_color = setsurface_color if fill else unsetsurface_color
|
|
|
|
# Testing the area parameter at different locations on the mask.
|
|
for pos in ((x, y) for y in range(height) for x in range(width)):
|
|
area_rect.topleft = pos
|
|
overlap_rect = mask_rect.clip(area_rect)
|
|
overlap_rect.topleft = (0, 0)
|
|
|
|
for use_color_params in (True, False):
|
|
surface.fill(surface_color) # Clear for each test.
|
|
test_kwargs = color_kwargs if use_color_params else kwargs
|
|
test_kwargs["area"].topleft = pos
|
|
overlap_rect = mask_rect.clip(test_kwargs["area"])
|
|
overlap_rect.topleft = (0, 0)
|
|
|
|
to_surface = mask.to_surface(**test_kwargs)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, overlap_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, overlap_rect
|
|
)
|
|
|
|
@unittest.expectedFailure
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_to_surface__area_off_mask(self):
|
|
"""Ensures area values off the mask work correctly
|
|
when using the defaults for setcolor and unsetcolor.
|
|
"""
|
|
default_setcolor = pygame.Color("white")
|
|
default_unsetcolor = pygame.Color("black")
|
|
width, height = size = (5, 7)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
surface_color = pygame.Color("red")
|
|
|
|
# Testing positions off the mask.
|
|
positions = [(-width, -height), (-width, 0), (0, -height)]
|
|
positions.extend(off_corners(pygame.Rect((0, 0), (width, height))))
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
area_rect = mask_rect.copy()
|
|
expected_color = default_setcolor if fill else default_unsetcolor
|
|
|
|
for pos in positions:
|
|
surface.fill(surface_color) # Clear for each test.
|
|
area_rect.topleft = pos
|
|
overlap_rect = mask_rect.clip(area_rect)
|
|
overlap_rect.topleft = (0, 0)
|
|
|
|
to_surface = mask.to_surface(surface, area=area_rect)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, overlap_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, overlap_rect
|
|
)
|
|
|
|
@unittest.expectedFailure
|
|
@unittest.skipIf(IS_PYPY, "Segfaults on pypy")
|
|
def test_to_surface__area_off_mask_with_setsurface_unsetsurface(self):
|
|
"""Ensures area values off the mask work correctly
|
|
when using setsurface and unsetsurface.
|
|
"""
|
|
width, height = size = (5, 7)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
surface_color = pygame.Color("red")
|
|
|
|
setsurface = surface.copy()
|
|
setsurface_color = pygame.Color("green")
|
|
setsurface.fill(setsurface_color)
|
|
|
|
unsetsurface = surface.copy()
|
|
unsetsurface_color = pygame.Color("blue")
|
|
unsetsurface.fill(unsetsurface_color)
|
|
|
|
# Testing positions off the mask.
|
|
positions = [(-width, -height), (-width, 0), (0, -height)]
|
|
positions.extend(off_corners(pygame.Rect((0, 0), (width, height))))
|
|
|
|
# Using the values in kwargs vs color_kwargs tests different to_surface
|
|
# code. Should not have any impact on the resulting drawn surfaces.
|
|
kwargs = {
|
|
"surface": surface,
|
|
"setsurface": setsurface,
|
|
"unsetsurface": unsetsurface,
|
|
"area": pygame.Rect((0, 0), size),
|
|
}
|
|
|
|
color_kwargs = dict(kwargs)
|
|
color_kwargs.update((("setcolor", None), ("unsetcolor", None)))
|
|
|
|
for fill in (True, False):
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
mask_rect = mask.get_rect()
|
|
expected_color = setsurface_color if fill else unsetsurface_color
|
|
|
|
for pos in positions:
|
|
for use_color_params in (True, False):
|
|
surface.fill(surface_color) # Clear for each test.
|
|
test_kwargs = color_kwargs if use_color_params else kwargs
|
|
test_kwargs["area"].topleft = pos
|
|
overlap_rect = mask_rect.clip(test_kwargs["area"])
|
|
overlap_rect.topleft = (0, 0)
|
|
|
|
to_surface = mask.to_surface(**test_kwargs)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color, overlap_rect)
|
|
assertSurfaceFilledIgnoreArea(
|
|
self, to_surface, surface_color, overlap_rect
|
|
)
|
|
|
|
def test_to_surface__surface_with_zero_size(self):
|
|
"""Ensures zero sized surfaces are handled correctly."""
|
|
expected_ref_count = 3
|
|
size = (0, 0)
|
|
surface = pygame.Surface(size)
|
|
mask = pygame.mask.Mask((3, 4), fill=True)
|
|
|
|
to_surface = mask.to_surface(surface)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
|
|
def test_to_surface__setsurface_with_zero_size(self):
|
|
"""Ensures zero sized setsurfaces are handled correctly."""
|
|
expected_ref_count = 2
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
expected_color = pygame.Color("white") # Default setcolor.
|
|
mask_size = (2, 4)
|
|
mask = pygame.mask.Mask(mask_size, fill=True)
|
|
setsurface = pygame.Surface((0, 0), expected_flag, expected_depth)
|
|
|
|
to_surface = mask.to_surface(setsurface=setsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(to_surface.get_bitsize(), expected_depth)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_to_surface__unsetsurface_with_zero_size(self):
|
|
"""Ensures zero sized unsetsurfaces are handled correctly."""
|
|
expected_ref_count = 2
|
|
expected_flag = SRCALPHA
|
|
expected_depth = 32
|
|
expected_color = pygame.Color("black") # Default unsetcolor.
|
|
mask_size = (4, 2)
|
|
mask = pygame.mask.Mask(mask_size)
|
|
unsetsurface = pygame.Surface((0, 0), expected_flag, expected_depth)
|
|
|
|
to_surface = mask.to_surface(unsetsurface=unsetsurface)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
if not IS_PYPY:
|
|
self.assertEqual(sys.getrefcount(to_surface), expected_ref_count)
|
|
self.assertTrue(to_surface.get_flags() & expected_flag)
|
|
self.assertEqual(to_surface.get_bitsize(), expected_depth)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
def test_zero_mask(self):
|
|
"""Ensures masks can be created with zero sizes."""
|
|
for size in ((100, 0), (0, 100), (0, 0)):
|
|
for fill in (True, False):
|
|
msg = f"size={size}, fill={fill}"
|
|
|
|
mask = pygame.mask.Mask(size, fill=fill)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.get_size(), size, msg)
|
|
|
|
def test_zero_mask_copy(self):
|
|
"""Ensures copy correctly handles zero sized masks."""
|
|
for expected_size in ((11, 0), (0, 11), (0, 0)):
|
|
mask = pygame.mask.Mask(expected_size)
|
|
|
|
mask_copy = mask.copy()
|
|
|
|
self.assertIsInstance(mask_copy, pygame.mask.Mask)
|
|
self.assertIsNot(mask_copy, mask)
|
|
assertMaskEqual(self, mask_copy, mask)
|
|
|
|
def test_zero_mask_get_size(self):
|
|
"""Ensures get_size correctly handles zero sized masks."""
|
|
for expected_size in ((41, 0), (0, 40), (0, 0)):
|
|
mask = pygame.mask.Mask(expected_size)
|
|
|
|
size = mask.get_size()
|
|
|
|
self.assertEqual(size, expected_size)
|
|
|
|
def test_zero_mask_get_rect(self):
|
|
"""Ensures get_rect correctly handles zero sized masks."""
|
|
for expected_size in ((4, 0), (0, 4), (0, 0)):
|
|
expected_rect = pygame.Rect((0, 0), expected_size)
|
|
mask = pygame.mask.Mask(expected_size)
|
|
|
|
rect = mask.get_rect()
|
|
|
|
self.assertEqual(rect, expected_rect)
|
|
|
|
def test_zero_mask_get_at(self):
|
|
"""Ensures get_at correctly handles zero sized masks."""
|
|
for size in ((51, 0), (0, 50), (0, 0)):
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
with self.assertRaises(IndexError):
|
|
value = mask.get_at((0, 0))
|
|
|
|
def test_zero_mask_set_at(self):
|
|
"""Ensures set_at correctly handles zero sized masks."""
|
|
for size in ((31, 0), (0, 30), (0, 0)):
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
with self.assertRaises(IndexError):
|
|
mask.set_at((0, 0))
|
|
|
|
def test_zero_mask_overlap(self):
|
|
"""Ensures overlap correctly handles zero sized masks.
|
|
|
|
Tests combinations of sized and zero sized masks.
|
|
"""
|
|
offset = (0, 0)
|
|
|
|
for size1, size2 in zero_size_pairs(51, 42):
|
|
msg = f"size1={size1}, size2={size2}"
|
|
mask1 = pygame.mask.Mask(size1, fill=True)
|
|
mask2 = pygame.mask.Mask(size2, fill=True)
|
|
|
|
overlap_pos = mask1.overlap(mask2, offset)
|
|
|
|
self.assertIsNone(overlap_pos, msg)
|
|
|
|
def test_zero_mask_overlap_area(self):
|
|
"""Ensures overlap_area correctly handles zero sized masks.
|
|
|
|
Tests combinations of sized and zero sized masks.
|
|
"""
|
|
offset = (0, 0)
|
|
expected_count = 0
|
|
|
|
for size1, size2 in zero_size_pairs(41, 52):
|
|
msg = f"size1={size1}, size2={size2}"
|
|
mask1 = pygame.mask.Mask(size1, fill=True)
|
|
mask2 = pygame.mask.Mask(size2, fill=True)
|
|
|
|
overlap_count = mask1.overlap_area(mask2, offset)
|
|
|
|
self.assertEqual(overlap_count, expected_count, msg)
|
|
|
|
def test_zero_mask_overlap_mask(self):
|
|
"""Ensures overlap_mask correctly handles zero sized masks.
|
|
|
|
Tests combinations of sized and zero sized masks.
|
|
"""
|
|
offset = (0, 0)
|
|
expected_count = 0
|
|
|
|
for size1, size2 in zero_size_pairs(43, 53):
|
|
msg = f"size1={size1}, size2={size2}"
|
|
mask1 = pygame.mask.Mask(size1, fill=True)
|
|
mask2 = pygame.mask.Mask(size2, fill=True)
|
|
|
|
overlap_mask = mask1.overlap_mask(mask2, offset)
|
|
|
|
self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(overlap_mask.count(), expected_count, msg)
|
|
self.assertEqual(overlap_mask.get_size(), size1, msg)
|
|
|
|
def test_zero_mask_fill(self):
|
|
"""Ensures fill correctly handles zero sized masks."""
|
|
expected_count = 0
|
|
|
|
for size in ((100, 0), (0, 100), (0, 0)):
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
mask.fill()
|
|
|
|
self.assertEqual(mask.count(), expected_count, f"size={size}")
|
|
|
|
def test_zero_mask_clear(self):
|
|
sizes = ((100, 0), (0, 100), (0, 0))
|
|
|
|
for size in sizes:
|
|
mask = pygame.mask.Mask(size)
|
|
mask.clear()
|
|
self.assertEqual(mask.count(), 0)
|
|
|
|
def test_zero_mask_flip(self):
|
|
sizes = ((100, 0), (0, 100), (0, 0))
|
|
|
|
for size in sizes:
|
|
mask = pygame.mask.Mask(size)
|
|
mask.invert()
|
|
self.assertEqual(mask.count(), 0)
|
|
|
|
def test_zero_mask_scale(self):
|
|
sizes = ((100, 0), (0, 100), (0, 0))
|
|
|
|
for size in sizes:
|
|
mask = pygame.mask.Mask(size)
|
|
mask2 = mask.scale((2, 3))
|
|
|
|
self.assertIsInstance(mask2, pygame.mask.Mask)
|
|
self.assertEqual(mask2.get_size(), (2, 3))
|
|
|
|
def test_zero_mask_draw(self):
|
|
"""Ensures draw correctly handles zero sized masks.
|
|
|
|
Tests combinations of sized and zero sized masks.
|
|
"""
|
|
offset = (0, 0)
|
|
|
|
for size1, size2 in zero_size_pairs(31, 37):
|
|
msg = f"size1={size1}, size2={size2}"
|
|
mask1 = pygame.mask.Mask(size1, fill=True)
|
|
mask2 = pygame.mask.Mask(size2, fill=True)
|
|
expected_count = mask1.count()
|
|
|
|
mask1.draw(mask2, offset)
|
|
|
|
self.assertEqual(mask1.count(), expected_count, msg)
|
|
self.assertEqual(mask1.get_size(), size1, msg)
|
|
|
|
def test_zero_mask_erase(self):
|
|
"""Ensures erase correctly handles zero sized masks.
|
|
|
|
Tests combinations of sized and zero sized masks.
|
|
"""
|
|
offset = (0, 0)
|
|
|
|
for size1, size2 in zero_size_pairs(29, 23):
|
|
msg = f"size1={size1}, size2={size2}"
|
|
mask1 = pygame.mask.Mask(size1, fill=True)
|
|
mask2 = pygame.mask.Mask(size2, fill=True)
|
|
expected_count = mask1.count()
|
|
|
|
mask1.erase(mask2, offset)
|
|
|
|
self.assertEqual(mask1.count(), expected_count, msg)
|
|
self.assertEqual(mask1.get_size(), size1, msg)
|
|
|
|
def test_zero_mask_count(self):
|
|
sizes = ((100, 0), (0, 100), (0, 0))
|
|
|
|
for size in sizes:
|
|
mask = pygame.mask.Mask(size, fill=True)
|
|
self.assertEqual(mask.count(), 0)
|
|
|
|
def test_zero_mask_centroid(self):
|
|
sizes = ((100, 0), (0, 100), (0, 0))
|
|
|
|
for size in sizes:
|
|
mask = pygame.mask.Mask(size)
|
|
self.assertEqual(mask.centroid(), (0, 0))
|
|
|
|
def test_zero_mask_angle(self):
|
|
sizes = ((100, 0), (0, 100), (0, 0))
|
|
|
|
for size in sizes:
|
|
mask = pygame.mask.Mask(size)
|
|
self.assertEqual(mask.angle(), 0.0)
|
|
|
|
def test_zero_mask_outline(self):
|
|
"""Ensures outline correctly handles zero sized masks."""
|
|
expected_points = []
|
|
|
|
for size in ((61, 0), (0, 60), (0, 0)):
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
points = mask.outline()
|
|
|
|
self.assertListEqual(points, expected_points, f"size={size}")
|
|
|
|
def test_zero_mask_outline__with_arg(self):
|
|
"""Ensures outline correctly handles zero sized masks
|
|
when using the skip pixels argument."""
|
|
expected_points = []
|
|
|
|
for size in ((66, 0), (0, 65), (0, 0)):
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
points = mask.outline(10)
|
|
|
|
self.assertListEqual(points, expected_points, f"size={size}")
|
|
|
|
def test_zero_mask_convolve(self):
|
|
"""Ensures convolve correctly handles zero sized masks.
|
|
|
|
Tests the different combinations of sized and zero sized masks.
|
|
"""
|
|
for size1 in ((17, 13), (71, 0), (0, 70), (0, 0)):
|
|
mask1 = pygame.mask.Mask(size1, fill=True)
|
|
|
|
for size2 in ((11, 7), (81, 0), (0, 60), (0, 0)):
|
|
msg = f"sizes={size1}, {size2}"
|
|
mask2 = pygame.mask.Mask(size2, fill=True)
|
|
expected_size = (
|
|
max(0, size1[0] + size2[0] - 1),
|
|
max(0, size1[1] + size2[1] - 1),
|
|
)
|
|
|
|
mask = mask1.convolve(mask2)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertIsNot(mask, mask2, msg)
|
|
self.assertEqual(mask.get_size(), expected_size, msg)
|
|
|
|
def test_zero_mask_convolve__with_output_mask(self):
|
|
"""Ensures convolve correctly handles zero sized masks
|
|
when using an output mask argument.
|
|
|
|
Tests the different combinations of sized and zero sized masks.
|
|
"""
|
|
for size1 in ((11, 17), (91, 0), (0, 90), (0, 0)):
|
|
mask1 = pygame.mask.Mask(size1, fill=True)
|
|
|
|
for size2 in ((13, 11), (83, 0), (0, 62), (0, 0)):
|
|
mask2 = pygame.mask.Mask(size2, fill=True)
|
|
|
|
for output_size in ((7, 5), (71, 0), (0, 70), (0, 0)):
|
|
msg = f"sizes={size1}, {size2}, {output_size}"
|
|
output_mask = pygame.mask.Mask(output_size)
|
|
|
|
mask = mask1.convolve(mask2, output_mask)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertIs(mask, output_mask, msg)
|
|
self.assertEqual(mask.get_size(), output_size, msg)
|
|
|
|
def test_zero_mask_connected_component(self):
|
|
"""Ensures connected_component correctly handles zero sized masks."""
|
|
expected_count = 0
|
|
|
|
for size in ((81, 0), (0, 80), (0, 0)):
|
|
msg = f"size={size}"
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
cc_mask = mask.connected_component()
|
|
|
|
self.assertIsInstance(cc_mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(cc_mask.get_size(), size)
|
|
self.assertEqual(cc_mask.count(), expected_count, msg)
|
|
|
|
def test_zero_mask_connected_component__indexed(self):
|
|
"""Ensures connected_component correctly handles zero sized masks
|
|
when using an index argument."""
|
|
for size in ((91, 0), (0, 90), (0, 0)):
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
with self.assertRaises(IndexError):
|
|
cc_mask = mask.connected_component((0, 0))
|
|
|
|
def test_zero_mask_connected_components(self):
|
|
"""Ensures connected_components correctly handles zero sized masks."""
|
|
expected_cc_masks = []
|
|
|
|
for size in ((11, 0), (0, 10), (0, 0)):
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
cc_masks = mask.connected_components()
|
|
|
|
self.assertListEqual(cc_masks, expected_cc_masks, f"size={size}")
|
|
|
|
def test_zero_mask_get_bounding_rects(self):
|
|
"""Ensures get_bounding_rects correctly handles zero sized masks."""
|
|
expected_bounding_rects = []
|
|
|
|
for size in ((21, 0), (0, 20), (0, 0)):
|
|
mask = pygame.mask.Mask(size)
|
|
|
|
bounding_rects = mask.get_bounding_rects()
|
|
|
|
self.assertListEqual(
|
|
bounding_rects, expected_bounding_rects, f"size={size}"
|
|
)
|
|
|
|
def test_zero_mask_to_surface(self):
|
|
"""Ensures to_surface correctly handles zero sized masks and surfaces."""
|
|
mask_color = pygame.Color("blue")
|
|
surf_color = pygame.Color("red")
|
|
|
|
for surf_size in ((7, 3), (7, 0), (0, 7), (0, 0)):
|
|
surface = pygame.Surface(surf_size, SRCALPHA, 32)
|
|
surface.fill(surf_color)
|
|
|
|
for mask_size in ((5, 0), (0, 5), (0, 0)):
|
|
mask = pygame.mask.Mask(mask_size, fill=True)
|
|
|
|
to_surface = mask.to_surface(surface, setcolor=mask_color)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), surf_size)
|
|
|
|
if 0 not in surf_size:
|
|
assertSurfaceFilled(self, to_surface, surf_color)
|
|
|
|
def test_zero_mask_to_surface__create_surface(self):
|
|
"""Ensures to_surface correctly handles zero sized masks and surfaces
|
|
when it has to create a default surface.
|
|
"""
|
|
mask_color = pygame.Color("blue")
|
|
|
|
for mask_size in ((3, 0), (0, 3), (0, 0)):
|
|
mask = pygame.mask.Mask(mask_size, fill=True)
|
|
|
|
to_surface = mask.to_surface(setcolor=mask_color)
|
|
|
|
self.assertIsInstance(to_surface, pygame.Surface)
|
|
self.assertEqual(to_surface.get_size(), mask_size)
|
|
|
|
|
|
class SubMask(pygame.mask.Mask):
|
|
"""Subclass of the Mask class to help test subclassing."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.test_attribute = True
|
|
|
|
|
|
class SubMaskCopy(SubMask):
|
|
"""Subclass of the Mask class to help test copying subclasses."""
|
|
|
|
def copy(self):
|
|
mask_copy = super().copy()
|
|
mask_copy.test_attribute = self.test_attribute
|
|
return mask_copy
|
|
|
|
|
|
class SubMaskDunderCopy(SubMask):
|
|
"""Subclass of the Mask class to help test copying subclasses."""
|
|
|
|
def __copy__(self):
|
|
mask_copy = super().__copy__()
|
|
mask_copy.test_attribute = self.test_attribute
|
|
return mask_copy
|
|
|
|
|
|
class SubMaskCopyAndDunderCopy(SubMaskDunderCopy):
|
|
"""Subclass of the Mask class to help test copying subclasses."""
|
|
|
|
def copy(self):
|
|
return super().copy()
|
|
|
|
|
|
class MaskSubclassTest(unittest.TestCase):
|
|
"""Test subclassed Masks."""
|
|
|
|
def test_subclass_mask(self):
|
|
"""Ensures the Mask class can be subclassed."""
|
|
mask = SubMask((5, 3), fill=True)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask)
|
|
self.assertIsInstance(mask, SubMask)
|
|
self.assertTrue(mask.test_attribute)
|
|
|
|
def test_subclass_copy(self):
|
|
"""Ensures copy works for subclassed Masks."""
|
|
mask = SubMask((65, 2), fill=True)
|
|
|
|
# Test both the copy() and __copy__() methods.
|
|
for mask_copy in (mask.copy(), copy.copy(mask)):
|
|
self.assertIsInstance(mask_copy, pygame.mask.Mask)
|
|
self.assertIsInstance(mask_copy, SubMask)
|
|
self.assertIsNot(mask_copy, mask)
|
|
assertMaskEqual(self, mask_copy, mask)
|
|
# No subclass attributes because copy()/__copy__() not overridden.
|
|
self.assertFalse(hasattr(mask_copy, "test_attribute"))
|
|
|
|
def test_subclass_copy__override_copy(self):
|
|
"""Ensures copy works for subclassed Masks overriding copy."""
|
|
mask = SubMaskCopy((65, 2), fill=True)
|
|
|
|
# Test both the copy() and __copy__() methods.
|
|
for i, mask_copy in enumerate((mask.copy(), copy.copy(mask))):
|
|
self.assertIsInstance(mask_copy, pygame.mask.Mask)
|
|
self.assertIsInstance(mask_copy, SubMaskCopy)
|
|
self.assertIsNot(mask_copy, mask)
|
|
assertMaskEqual(self, mask_copy, mask)
|
|
|
|
if 1 == i:
|
|
# No subclass attributes because __copy__() not overridden.
|
|
self.assertFalse(hasattr(mask_copy, "test_attribute"))
|
|
else:
|
|
self.assertTrue(mask_copy.test_attribute)
|
|
|
|
def test_subclass_copy__override_dunder_copy(self):
|
|
"""Ensures copy works for subclassed Masks overriding __copy__."""
|
|
mask = SubMaskDunderCopy((65, 2), fill=True)
|
|
|
|
# Test both the copy() and __copy__() methods.
|
|
for mask_copy in (mask.copy(), copy.copy(mask)):
|
|
self.assertIsInstance(mask_copy, pygame.mask.Mask)
|
|
self.assertIsInstance(mask_copy, SubMaskDunderCopy)
|
|
self.assertIsNot(mask_copy, mask)
|
|
assertMaskEqual(self, mask_copy, mask)
|
|
# Calls to copy() eventually call __copy__() internally so the
|
|
# attributes will be copied.
|
|
self.assertTrue(mask_copy.test_attribute)
|
|
|
|
def test_subclass_copy__override_both_copy_methods(self):
|
|
"""Ensures copy works for subclassed Masks overriding copy/__copy__."""
|
|
mask = SubMaskCopyAndDunderCopy((65, 2), fill=True)
|
|
|
|
# Test both the copy() and __copy__() methods.
|
|
for mask_copy in (mask.copy(), copy.copy(mask)):
|
|
self.assertIsInstance(mask_copy, pygame.mask.Mask)
|
|
self.assertIsInstance(mask_copy, SubMaskCopyAndDunderCopy)
|
|
self.assertIsNot(mask_copy, mask)
|
|
assertMaskEqual(self, mask_copy, mask)
|
|
self.assertTrue(mask_copy.test_attribute)
|
|
|
|
def test_subclass_get_size(self):
|
|
"""Ensures get_size works for subclassed Masks."""
|
|
expected_size = (2, 3)
|
|
mask = SubMask(expected_size)
|
|
|
|
size = mask.get_size()
|
|
|
|
self.assertEqual(size, expected_size)
|
|
|
|
def test_subclass_mask_get_rect(self):
|
|
"""Ensures get_rect works for subclassed Masks."""
|
|
expected_rect = pygame.Rect((0, 0), (65, 33))
|
|
mask = SubMask(expected_rect.size, fill=True)
|
|
|
|
rect = mask.get_rect()
|
|
|
|
self.assertEqual(rect, expected_rect)
|
|
|
|
def test_subclass_get_at(self):
|
|
"""Ensures get_at works for subclassed Masks."""
|
|
expected_bit = 1
|
|
mask = SubMask((3, 2), fill=True)
|
|
|
|
bit = mask.get_at((0, 0))
|
|
|
|
self.assertEqual(bit, expected_bit)
|
|
|
|
def test_subclass_set_at(self):
|
|
"""Ensures set_at works for subclassed Masks."""
|
|
expected_bit = 1
|
|
expected_count = 1
|
|
pos = (0, 0)
|
|
mask = SubMask(fill=False, size=(4, 2))
|
|
|
|
mask.set_at(pos)
|
|
|
|
self.assertEqual(mask.get_at(pos), expected_bit)
|
|
self.assertEqual(mask.count(), expected_count)
|
|
|
|
def test_subclass_overlap(self):
|
|
"""Ensures overlap works for subclassed Masks."""
|
|
expected_pos = (0, 0)
|
|
mask_size = (2, 3)
|
|
masks = (pygame.mask.Mask(fill=True, size=mask_size), SubMask(mask_size, True))
|
|
arg_masks = (
|
|
pygame.mask.Mask(fill=True, size=mask_size),
|
|
SubMask(mask_size, True),
|
|
)
|
|
|
|
# Test different combinations of subclassed and non-subclassed Masks.
|
|
for mask in masks:
|
|
for arg_mask in arg_masks:
|
|
overlap_pos = mask.overlap(arg_mask, (0, 0))
|
|
|
|
self.assertEqual(overlap_pos, expected_pos)
|
|
|
|
def test_subclass_overlap_area(self):
|
|
"""Ensures overlap_area works for subclassed Masks."""
|
|
mask_size = (3, 2)
|
|
expected_count = mask_size[0] * mask_size[1]
|
|
masks = (pygame.mask.Mask(fill=True, size=mask_size), SubMask(mask_size, True))
|
|
arg_masks = (
|
|
pygame.mask.Mask(fill=True, size=mask_size),
|
|
SubMask(mask_size, True),
|
|
)
|
|
|
|
# Test different combinations of subclassed and non-subclassed Masks.
|
|
for mask in masks:
|
|
for arg_mask in arg_masks:
|
|
overlap_count = mask.overlap_area(arg_mask, (0, 0))
|
|
|
|
self.assertEqual(overlap_count, expected_count)
|
|
|
|
def test_subclass_overlap_mask(self):
|
|
"""Ensures overlap_mask works for subclassed Masks."""
|
|
expected_size = (4, 5)
|
|
expected_count = expected_size[0] * expected_size[1]
|
|
masks = (
|
|
pygame.mask.Mask(fill=True, size=expected_size),
|
|
SubMask(expected_size, True),
|
|
)
|
|
arg_masks = (
|
|
pygame.mask.Mask(fill=True, size=expected_size),
|
|
SubMask(expected_size, True),
|
|
)
|
|
|
|
# Test different combinations of subclassed and non-subclassed Masks.
|
|
for mask in masks:
|
|
for arg_mask in arg_masks:
|
|
overlap_mask = mask.overlap_mask(arg_mask, (0, 0))
|
|
|
|
self.assertIsInstance(overlap_mask, pygame.mask.Mask)
|
|
self.assertNotIsInstance(overlap_mask, SubMask)
|
|
self.assertEqual(overlap_mask.count(), expected_count)
|
|
self.assertEqual(overlap_mask.get_size(), expected_size)
|
|
|
|
def test_subclass_fill(self):
|
|
"""Ensures fill works for subclassed Masks."""
|
|
mask_size = (2, 4)
|
|
expected_count = mask_size[0] * mask_size[1]
|
|
mask = SubMask(fill=False, size=mask_size)
|
|
|
|
mask.fill()
|
|
|
|
self.assertEqual(mask.count(), expected_count)
|
|
|
|
def test_subclass_clear(self):
|
|
"""Ensures clear works for subclassed Masks."""
|
|
mask_size = (4, 3)
|
|
expected_count = 0
|
|
mask = SubMask(mask_size, True)
|
|
|
|
mask.clear()
|
|
|
|
self.assertEqual(mask.count(), expected_count)
|
|
|
|
def test_subclass_invert(self):
|
|
"""Ensures invert works for subclassed Masks."""
|
|
mask_size = (1, 4)
|
|
expected_count = mask_size[0] * mask_size[1]
|
|
mask = SubMask(fill=False, size=mask_size)
|
|
|
|
mask.invert()
|
|
|
|
self.assertEqual(mask.count(), expected_count)
|
|
|
|
def test_subclass_scale(self):
|
|
"""Ensures scale works for subclassed Masks."""
|
|
expected_size = (5, 2)
|
|
mask = SubMask((1, 4))
|
|
|
|
scaled_mask = mask.scale(expected_size)
|
|
|
|
self.assertIsInstance(scaled_mask, pygame.mask.Mask)
|
|
self.assertNotIsInstance(scaled_mask, SubMask)
|
|
self.assertEqual(scaled_mask.get_size(), expected_size)
|
|
|
|
def test_subclass_draw(self):
|
|
"""Ensures draw works for subclassed Masks."""
|
|
mask_size = (5, 4)
|
|
expected_count = mask_size[0] * mask_size[1]
|
|
arg_masks = (
|
|
pygame.mask.Mask(fill=True, size=mask_size),
|
|
SubMask(mask_size, True),
|
|
)
|
|
|
|
# Test different combinations of subclassed and non-subclassed Masks.
|
|
for mask in (pygame.mask.Mask(mask_size), SubMask(mask_size)):
|
|
for arg_mask in arg_masks:
|
|
mask.clear() # Clear for each test.
|
|
|
|
mask.draw(arg_mask, (0, 0))
|
|
|
|
self.assertEqual(mask.count(), expected_count)
|
|
|
|
def test_subclass_erase(self):
|
|
"""Ensures erase works for subclassed Masks."""
|
|
mask_size = (3, 4)
|
|
expected_count = 0
|
|
masks = (pygame.mask.Mask(mask_size, True), SubMask(mask_size, True))
|
|
arg_masks = (pygame.mask.Mask(mask_size, True), SubMask(mask_size, True))
|
|
|
|
# Test different combinations of subclassed and non-subclassed Masks.
|
|
for mask in masks:
|
|
for arg_mask in arg_masks:
|
|
mask.fill() # Fill for each test.
|
|
|
|
mask.erase(arg_mask, (0, 0))
|
|
|
|
self.assertEqual(mask.count(), expected_count)
|
|
|
|
def test_subclass_count(self):
|
|
"""Ensures count works for subclassed Masks."""
|
|
mask_size = (5, 2)
|
|
expected_count = mask_size[0] * mask_size[1] - 1
|
|
mask = SubMask(fill=True, size=mask_size)
|
|
mask.set_at((1, 1), 0)
|
|
|
|
count = mask.count()
|
|
|
|
self.assertEqual(count, expected_count)
|
|
|
|
def test_subclass_centroid(self):
|
|
"""Ensures centroid works for subclassed Masks."""
|
|
expected_centroid = (0, 0)
|
|
mask_size = (3, 2)
|
|
mask = SubMask((3, 2))
|
|
|
|
centroid = mask.centroid()
|
|
|
|
self.assertEqual(centroid, expected_centroid)
|
|
|
|
def test_subclass_angle(self):
|
|
"""Ensures angle works for subclassed Masks."""
|
|
expected_angle = 0.0
|
|
mask = SubMask(size=(5, 4))
|
|
|
|
angle = mask.angle()
|
|
|
|
self.assertAlmostEqual(angle, expected_angle)
|
|
|
|
def test_subclass_outline(self):
|
|
"""Ensures outline works for subclassed Masks."""
|
|
expected_outline = []
|
|
mask = SubMask((3, 4))
|
|
|
|
outline = mask.outline()
|
|
|
|
self.assertListEqual(outline, expected_outline)
|
|
|
|
def test_subclass_convolve(self):
|
|
"""Ensures convolve works for subclassed Masks."""
|
|
width, height = 7, 5
|
|
mask_size = (width, height)
|
|
expected_count = 0
|
|
expected_size = (max(0, width * 2 - 1), max(0, height * 2 - 1))
|
|
|
|
arg_masks = (pygame.mask.Mask(mask_size), SubMask(mask_size))
|
|
output_masks = (pygame.mask.Mask(mask_size), SubMask(mask_size))
|
|
|
|
# Test different combinations of subclassed and non-subclassed Masks.
|
|
for mask in (pygame.mask.Mask(mask_size), SubMask(mask_size)):
|
|
for arg_mask in arg_masks:
|
|
convolve_mask = mask.convolve(arg_mask)
|
|
|
|
self.assertIsInstance(convolve_mask, pygame.mask.Mask)
|
|
self.assertNotIsInstance(convolve_mask, SubMask)
|
|
self.assertEqual(convolve_mask.count(), expected_count)
|
|
self.assertEqual(convolve_mask.get_size(), expected_size)
|
|
|
|
# Test subclassed masks for the output_mask as well.
|
|
for output_mask in output_masks:
|
|
convolve_mask = mask.convolve(arg_mask, output_mask)
|
|
|
|
self.assertIsInstance(convolve_mask, pygame.mask.Mask)
|
|
self.assertEqual(convolve_mask.count(), expected_count)
|
|
self.assertEqual(convolve_mask.get_size(), mask_size)
|
|
|
|
if isinstance(output_mask, SubMask):
|
|
self.assertIsInstance(convolve_mask, SubMask)
|
|
else:
|
|
self.assertNotIsInstance(convolve_mask, SubMask)
|
|
|
|
def test_subclass_connected_component(self):
|
|
"""Ensures connected_component works for subclassed Masks."""
|
|
expected_count = 0
|
|
expected_size = (3, 4)
|
|
mask = SubMask(expected_size)
|
|
|
|
cc_mask = mask.connected_component()
|
|
|
|
self.assertIsInstance(cc_mask, pygame.mask.Mask)
|
|
self.assertNotIsInstance(cc_mask, SubMask)
|
|
self.assertEqual(cc_mask.count(), expected_count)
|
|
self.assertEqual(cc_mask.get_size(), expected_size)
|
|
|
|
def test_subclass_connected_components(self):
|
|
"""Ensures connected_components works for subclassed Masks."""
|
|
expected_ccs = []
|
|
mask = SubMask((5, 4))
|
|
|
|
ccs = mask.connected_components()
|
|
|
|
self.assertListEqual(ccs, expected_ccs)
|
|
|
|
def test_subclass_get_bounding_rects(self):
|
|
"""Ensures get_bounding_rects works for subclassed Masks."""
|
|
expected_bounding_rects = []
|
|
mask = SubMask((3, 2))
|
|
|
|
bounding_rects = mask.get_bounding_rects()
|
|
|
|
self.assertListEqual(bounding_rects, expected_bounding_rects)
|
|
|
|
def test_subclass_to_surface(self):
|
|
"""Ensures to_surface works for subclassed Masks."""
|
|
expected_color = pygame.Color("blue")
|
|
size = (5, 3)
|
|
mask = SubMask(size, fill=True)
|
|
surface = pygame.Surface(size, SRCALPHA, 32)
|
|
surface.fill(pygame.Color("red"))
|
|
|
|
to_surface = mask.to_surface(surface, setcolor=expected_color)
|
|
|
|
self.assertIs(to_surface, surface)
|
|
self.assertEqual(to_surface.get_size(), size)
|
|
assertSurfaceFilled(self, to_surface, expected_color)
|
|
|
|
|
|
@unittest.skipIf(IS_PYPY, "pypy has lots of mask failures") # TODO
|
|
class MaskModuleTest(unittest.TestCase):
|
|
def test_from_surface(self):
|
|
"""Ensures from_surface creates a mask with the correct bits set.
|
|
|
|
This test checks the masks created by the from_surface function using
|
|
16 and 32 bit surfaces. Each alpha value (0-255) is tested against
|
|
several different threshold values.
|
|
Note: On 16 bit surface the requested alpha value can differ from what
|
|
is actually set. This test uses the value read from the surface.
|
|
"""
|
|
threshold_count = 256
|
|
surface_color = [55, 155, 255, 0]
|
|
expected_size = (11, 9)
|
|
all_set_count = expected_size[0] * expected_size[1]
|
|
none_set_count = 0
|
|
|
|
for depth in (16, 32):
|
|
surface = pygame.Surface(expected_size, SRCALPHA, depth)
|
|
|
|
for alpha in range(threshold_count):
|
|
surface_color[3] = alpha
|
|
surface.fill(surface_color)
|
|
|
|
if depth < 32:
|
|
# On surfaces with depths < 32 the requested alpha can be
|
|
# different than what gets set. Use the value read from the
|
|
# surface.
|
|
alpha = surface.get_at((0, 0))[3]
|
|
|
|
# Test the mask created at threshold values low, high and
|
|
# around alpha.
|
|
threshold_test_values = {-1, 0, alpha - 1, alpha, alpha + 1, 255, 256}
|
|
|
|
for threshold in threshold_test_values:
|
|
msg = f"depth={depth}, alpha={alpha}, threshold={threshold}"
|
|
|
|
if alpha > threshold:
|
|
expected_count = all_set_count
|
|
else:
|
|
expected_count = none_set_count
|
|
|
|
mask = pygame.mask.from_surface(
|
|
surface=surface, threshold=threshold
|
|
)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.get_size(), expected_size, msg)
|
|
self.assertEqual(mask.count(), expected_count, msg)
|
|
|
|
def test_from_surface__different_alphas_32bit(self):
|
|
"""Ensures from_surface creates a mask with the correct bits set
|
|
when pixels have different alpha values (32 bits surfaces).
|
|
|
|
This test checks the masks created by the from_surface function using
|
|
a 32 bit surface. The surface is created with each pixel having a
|
|
different alpha value (0-255). This surface is tested over a range
|
|
of threshold values (0-255).
|
|
"""
|
|
offset = (0, 0)
|
|
threshold_count = 256
|
|
surface_color = [10, 20, 30, 0]
|
|
expected_size = (threshold_count, 1)
|
|
expected_mask = pygame.Mask(expected_size, fill=True)
|
|
surface = pygame.Surface(expected_size, SRCALPHA, 32)
|
|
|
|
# Give each pixel a different alpha.
|
|
surface.lock() # Lock for possible speed up.
|
|
for a in range(threshold_count):
|
|
surface_color[3] = a
|
|
surface.set_at((a, 0), surface_color)
|
|
surface.unlock()
|
|
|
|
# Test the mask created for each different alpha threshold.
|
|
for threshold in range(threshold_count):
|
|
msg = f"threshold={threshold}"
|
|
expected_mask.set_at((threshold, 0), 0)
|
|
expected_count = expected_mask.count()
|
|
|
|
mask = pygame.mask.from_surface(surface, threshold)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.get_size(), expected_size, msg)
|
|
self.assertEqual(mask.count(), expected_count, msg)
|
|
self.assertEqual(
|
|
mask.overlap_area(expected_mask, offset), expected_count, msg
|
|
)
|
|
|
|
def test_from_surface__different_alphas_16bit(self):
|
|
"""Ensures from_surface creates a mask with the correct bits set
|
|
when pixels have different alpha values (16 bit surfaces).
|
|
|
|
This test checks the masks created by the from_surface function using
|
|
a 16 bit surface. Each pixel of the surface is set with a different
|
|
alpha value (0-255), but since this is a 16 bit surface the requested
|
|
alpha value can differ from what is actually set. The resulting surface
|
|
will have groups of alpha values which complicates the test as the
|
|
alpha groups will all be set/unset at a given threshold. The setup
|
|
calculates these groups and an expected mask for each. This test data
|
|
is then used to test each alpha grouping over a range of threshold
|
|
values.
|
|
"""
|
|
threshold_count = 256
|
|
surface_color = [110, 120, 130, 0]
|
|
expected_size = (threshold_count, 1)
|
|
surface = pygame.Surface(expected_size, SRCALPHA, 16)
|
|
|
|
# Give each pixel a different alpha.
|
|
surface.lock() # Lock for possible speed up.
|
|
for a in range(threshold_count):
|
|
surface_color[3] = a
|
|
surface.set_at((a, 0), surface_color)
|
|
surface.unlock()
|
|
|
|
alpha_thresholds = OrderedDict()
|
|
special_thresholds = set()
|
|
|
|
# Create the threshold ranges and identify any thresholds that need
|
|
# special handling.
|
|
for threshold in range(threshold_count):
|
|
# On surfaces with depths < 32 the requested alpha can be different
|
|
# than what gets set. Use the value read from the surface.
|
|
alpha = surface.get_at((threshold, 0))[3]
|
|
|
|
if alpha not in alpha_thresholds:
|
|
alpha_thresholds[alpha] = [threshold]
|
|
else:
|
|
alpha_thresholds[alpha].append(threshold)
|
|
|
|
if threshold < alpha:
|
|
special_thresholds.add(threshold)
|
|
|
|
# Use each threshold group to create an expected mask.
|
|
test_data = [] # [(from_threshold, to_threshold, expected_mask), ...]
|
|
offset = (0, 0)
|
|
erase_mask = pygame.Mask(expected_size)
|
|
exp_mask = pygame.Mask(expected_size, fill=True)
|
|
|
|
for thresholds in alpha_thresholds.values():
|
|
for threshold in thresholds:
|
|
if threshold in special_thresholds:
|
|
# Any special thresholds just reuse previous exp_mask.
|
|
test_data.append((threshold, threshold + 1, exp_mask))
|
|
else:
|
|
to_threshold = thresholds[-1] + 1
|
|
|
|
# Make the expected mask by erasing the unset bits.
|
|
for thres in range(to_threshold):
|
|
erase_mask.set_at((thres, 0), 1)
|
|
|
|
exp_mask = pygame.Mask(expected_size, fill=True)
|
|
exp_mask.erase(erase_mask, offset)
|
|
test_data.append((threshold, to_threshold, exp_mask))
|
|
break
|
|
|
|
# All the setup is done. Now test the masks created over the threshold
|
|
# ranges.
|
|
for from_threshold, to_threshold, expected_mask in test_data:
|
|
expected_count = expected_mask.count()
|
|
|
|
for threshold in range(from_threshold, to_threshold):
|
|
msg = f"threshold={threshold}"
|
|
|
|
mask = pygame.mask.from_surface(surface, threshold)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.get_size(), expected_size, msg)
|
|
self.assertEqual(mask.count(), expected_count, msg)
|
|
self.assertEqual(
|
|
mask.overlap_area(expected_mask, offset), expected_count, msg
|
|
)
|
|
|
|
def test_from_surface__with_colorkey_mask_cleared(self):
|
|
"""Ensures from_surface creates a mask with the correct bits set
|
|
when the surface uses a colorkey.
|
|
|
|
The surface is filled with the colorkey color so the resulting masks
|
|
are expected to have no bits set.
|
|
"""
|
|
colorkeys = ((0, 0, 0), (1, 2, 3), (50, 100, 200), (255, 255, 255))
|
|
expected_size = (7, 11)
|
|
expected_count = 0
|
|
|
|
for depth in (8, 16, 24, 32):
|
|
msg = f"depth={depth}"
|
|
surface = pygame.Surface(expected_size, 0, depth)
|
|
|
|
for colorkey in colorkeys:
|
|
surface.set_colorkey(colorkey)
|
|
# With some depths (i.e. 8 and 16) the actual colorkey can be
|
|
# different than what was requested via the set.
|
|
surface.fill(surface.get_colorkey())
|
|
|
|
mask = pygame.mask.from_surface(surface)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.get_size(), expected_size, msg)
|
|
self.assertEqual(mask.count(), expected_count, msg)
|
|
|
|
def test_from_surface__with_colorkey_mask_filled(self):
|
|
"""Ensures from_surface creates a mask with the correct bits set
|
|
when the surface uses a colorkey.
|
|
|
|
The surface is filled with a color that is not the colorkey color so
|
|
the resulting masks are expected to have all bits set.
|
|
"""
|
|
colorkeys = ((0, 0, 0), (1, 2, 3), (10, 100, 200), (255, 255, 255))
|
|
surface_color = (50, 100, 200)
|
|
expected_size = (11, 7)
|
|
expected_count = expected_size[0] * expected_size[1]
|
|
|
|
for depth in (8, 16, 24, 32):
|
|
msg = f"depth={depth}"
|
|
surface = pygame.Surface(expected_size, 0, depth)
|
|
surface.fill(surface_color)
|
|
|
|
for colorkey in colorkeys:
|
|
surface.set_colorkey(colorkey)
|
|
|
|
mask = pygame.mask.from_surface(surface)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.get_size(), expected_size, msg)
|
|
self.assertEqual(mask.count(), expected_count, msg)
|
|
|
|
def test_from_surface__with_colorkey_mask_pattern(self):
|
|
"""Ensures from_surface creates a mask with the correct bits set
|
|
when the surface uses a colorkey.
|
|
|
|
The surface is filled with alternating pixels of colorkey and
|
|
non-colorkey colors, so the resulting masks are expected to have
|
|
alternating bits set.
|
|
"""
|
|
|
|
def alternate(func, set_value, unset_value, width, height):
|
|
# Helper function to set alternating values.
|
|
setbit = False
|
|
for pos in ((x, y) for x in range(width) for y in range(height)):
|
|
func(pos, set_value if setbit else unset_value)
|
|
setbit = not setbit
|
|
|
|
surface_color = (5, 10, 20)
|
|
colorkey = (50, 60, 70)
|
|
expected_size = (11, 2)
|
|
expected_mask = pygame.mask.Mask(expected_size)
|
|
alternate(expected_mask.set_at, 1, 0, *expected_size)
|
|
expected_count = expected_mask.count()
|
|
offset = (0, 0)
|
|
|
|
for depth in (8, 16, 24, 32):
|
|
msg = f"depth={depth}"
|
|
surface = pygame.Surface(expected_size, 0, depth)
|
|
# Fill the surface with alternating colors.
|
|
alternate(surface.set_at, surface_color, colorkey, *expected_size)
|
|
surface.set_colorkey(colorkey)
|
|
|
|
mask = pygame.mask.from_surface(surface)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask, msg)
|
|
self.assertEqual(mask.get_size(), expected_size, msg)
|
|
self.assertEqual(mask.count(), expected_count, msg)
|
|
self.assertEqual(
|
|
mask.overlap_area(expected_mask, offset), expected_count, msg
|
|
)
|
|
|
|
def test_from_threshold(self):
|
|
"""Does mask.from_threshold() work correctly?"""
|
|
|
|
a = [16, 24, 32]
|
|
|
|
for i in a:
|
|
surf = pygame.surface.Surface((70, 70), 0, i)
|
|
surf.fill((100, 50, 200), (20, 20, 20, 20))
|
|
mask = pygame.mask.from_threshold(
|
|
surf, (100, 50, 200, 255), (10, 10, 10, 255)
|
|
)
|
|
|
|
rects = mask.get_bounding_rects()
|
|
|
|
self.assertEqual(mask.count(), 400)
|
|
self.assertEqual(mask.get_bounding_rects(), [pygame.Rect((20, 20, 20, 20))])
|
|
|
|
for i in a:
|
|
surf = pygame.surface.Surface((70, 70), 0, i)
|
|
surf2 = pygame.surface.Surface((70, 70), 0, i)
|
|
surf.fill((100, 100, 100))
|
|
surf2.fill((150, 150, 150))
|
|
surf2.fill((100, 100, 100), (40, 40, 10, 10))
|
|
mask = pygame.mask.from_threshold(
|
|
surface=surf,
|
|
color=(0, 0, 0, 0),
|
|
threshold=(10, 10, 10, 255),
|
|
othersurface=surf2,
|
|
)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask)
|
|
self.assertEqual(mask.count(), 100)
|
|
self.assertEqual(mask.get_bounding_rects(), [pygame.Rect((40, 40, 10, 10))])
|
|
|
|
def test_zero_size_from_surface(self):
|
|
"""Ensures from_surface can create masks from zero sized surfaces."""
|
|
for size in ((100, 0), (0, 100), (0, 0)):
|
|
mask = pygame.mask.from_surface(pygame.Surface(size))
|
|
|
|
self.assertIsInstance(mask, pygame.mask.MaskType, f"size={size}")
|
|
self.assertEqual(mask.get_size(), size)
|
|
|
|
def test_zero_size_from_threshold(self):
|
|
a = [16, 24, 32]
|
|
sizes = ((100, 0), (0, 100), (0, 0))
|
|
|
|
for size in sizes:
|
|
for i in a:
|
|
surf = pygame.surface.Surface(size, 0, i)
|
|
surf.fill((100, 50, 200), (20, 20, 20, 20))
|
|
mask = pygame.mask.from_threshold(
|
|
surf, (100, 50, 200, 255), (10, 10, 10, 255)
|
|
)
|
|
|
|
self.assertEqual(mask.count(), 0)
|
|
|
|
rects = mask.get_bounding_rects()
|
|
self.assertEqual(rects, [])
|
|
|
|
for i in a:
|
|
surf = pygame.surface.Surface(size, 0, i)
|
|
surf2 = pygame.surface.Surface(size, 0, i)
|
|
surf.fill((100, 100, 100))
|
|
surf2.fill((150, 150, 150))
|
|
surf2.fill((100, 100, 100), (40, 40, 10, 10))
|
|
mask = pygame.mask.from_threshold(
|
|
surf, (0, 0, 0, 0), (10, 10, 10, 255), surf2
|
|
)
|
|
|
|
self.assertIsInstance(mask, pygame.mask.Mask)
|
|
self.assertEqual(mask.count(), 0)
|
|
|
|
rects = mask.get_bounding_rects()
|
|
self.assertEqual(rects, [])
|
|
|
|
def test_buffer_interface(self):
|
|
size = (1000, 100)
|
|
pixels_set = ((0, 1), (100, 10), (173, 90))
|
|
pixels_unset = ((0, 0), (101, 10), (173, 91))
|
|
|
|
mask = pygame.Mask(size)
|
|
for point in pixels_set:
|
|
mask.set_at(point, 1)
|
|
|
|
view = memoryview(mask)
|
|
intwidth = 8 * view.strides[1]
|
|
|
|
for point in pixels_set:
|
|
x, y = point
|
|
col = x // intwidth
|
|
self.assertEqual(
|
|
(view[col, y] >> (x % intwidth)) & 1,
|
|
1,
|
|
f"the pixel at {point} is not set to 1",
|
|
)
|
|
|
|
for point in pixels_unset:
|
|
x, y = point
|
|
col = x // intwidth
|
|
self.assertEqual(
|
|
(view[col, y] >> (x % intwidth)) & 1,
|
|
0,
|
|
f"the pixel at {point} is not set to 0",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|