All right, we'll both be figuring this one out at the same time. First off, a quick explanation of m_Mask:
m_Mask is a 2-dimensional array of ints:
int[,] m_Mask.
Each entry in the array represents (up to) 32 pixels horizontally of the collision mask for that sprite. So, for example, if your sprite is 64x64, then the dimensions of the mask would be [64,2]. That's 64 rows and 2 columns. An int takes up 32 bits of memory, so it's being used here as a bitmap. Wherever there's a 1, it's a solid pixel. If it's 0, it's not solid. So for a 64x64 sprite that was completely solid (a big ol' block), each bit of each entry in the array would be set to 1.
To simplify: imagine that m_Mask is instead an array of bits. It's size is [64,64], and each entry represent a pixel within the sprite. 1 means solid, 0 means empty. The only difference when using ints is that you're grouping horizontal sets of pixels together in sets of 32, for faster calculation later, using the binary & operator.
Quick side trip: The binary & operator compares two integers and returns a result where each bit is set to 1 if and only if both of the inputs had that bit also set to 1. So, for example 1011 & 1110 = 1010. Basically, it finds those bits that are common between the two inputs.
So, when you have two masks of two different sprite, and you know where there rectangles overlap, you can find which entries in the m_Mask array to compare, get the correct offset within those entries (unless the overlap is directly on a 32-bit boundary) then use the binary & operator. If the value returned is not 0, then at least one bit is set in the same place of each mask, ergo, those pixels overlap (a collision!) Let's go through the code and I'll try to explain it.
//By this time, the collision rectangle, that is, the intersection rectangle of the bounds of each sprite, has been calculated.
//Loop through each row of the collision rectangle
for(int y=0; y < maxY; y++) {
//Loop through each column of the collision rectangle, 32 columns at a time
for(int x=0; x < maxX; x+=32) {
//myMinX is the leftmost edge of the intersection rectangle relative to this sprite. We want to find out which int to look at horizontally by
//determining how many multiples of 32 (x+myMinX) is equal to. So when we access m_Mask, we'll be using m_Mask[??,myColIdx]
int myColIdx = (int)((x+myMinX)/32);
//myColOff determines the offset of the entry in m_Mask where myMinX points to. If myMinX is a multiple of 32, then the offset is 0. If
//myMinX is, for example, 34 or 66, then the offset is 2. This is the first bit in the mask we want to compare.
int myColOff = myMinX % 32;
//The following calculates the same information for the other sprite.
int targetColIdx = (int)((x+targetMinX)/32);
int targetColOff = targetMinX % 32;
//Now we access the actual mask, and shift it by the offset.
int myMask = m_Mask[y+myMinY,myColIdx] << myColOff;
//Same as above, for the other sprite.
int targetMask = target.m_Mask[y+targetMinY,targetColIdx] << targetColOff;
//The following is magic. You are not expected to understand.
if (myColOff != 0)
{
if (myColIdx + 1 < m_Mask.GetUpperBound(1))
myMask |= (m_Mask[y+myMinY,myColIdx+1] >> (32-myColOff)) &
~(unchecked((int)0x80000000) >> (31-myColOff));
}
else if (targetColOff != 0)
{
if (targetColIdx + 1 < target.m_Mask.GetUpperBound(1))
targetMask |= (target.m_Mask[y+targetMinY,targetColIdx+1] >> (32-targetColOff)) &
~(unchecked((int)0x80000000) >> (31-targetColOff));
}
//Now, myMask and targetMask represent the same location in space, for each sprite. Now, we check if they overlap, using the binary & operator.
if ((myMask & targetMask) != 0) {
//Okay, they overlap, since they have at least one bit in common.
}
}
}
So we need to modify that last bit to just find out which bits are common, add the x and y offsets to those bits, and we should technically be done:
int overlap = myMask & targetMask;
if (overlap != 0) {
int pY= y;
for (int i = 0; i < 32; ++i) {
if ((overlap & 1 << i) != 0) {
//This is a pixel overlap.
int pX = x + myMinX + i;
result.Add(new Point(pX,pY));
}
}
}
That's almost right. I haven't tested it, and right now, the return values are in sprite-local coordinates. If you need it in global coordinates, you'll need to add the offset of the sprite to pX and pY before adding it to result. Please let me know if this is total garbage and I'm way off.