public static unsafe byte[] GetMaskFromImage(Bitmap bmp) { int stride = ((bmp.Width + 7) / 8) * 8; FastBitArray arr = new FastBitArray(stride * bmp.Height); int strideFactor = 0; var data = bmp.BasicLockBits(); int bmpStride = data.Stride / 4; uint *ptrInt = (uint *)data.Scan0; for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { if (*(ptrInt + x + (y * bmpStride)) == 0xFFFFFFFFu) { arr.SetTrueReverse(x + strideFactor); } } strideFactor += stride; } bmp.UnlockBits(data); return(arr.ToByteArray()); }
public static unsafe FastBitArray GetMaskForBitmap(Bitmap bmp, AssetSprite spr, ref Rect maskbbox, FastBitArray existingMask = null) { int stride = ((spr.Width + 7) / 8) * 8; FastBitArray res = existingMask ?? new FastBitArray(stride * spr.Height); Rect bbox = GetBBoxForBitmap(bmp, spr); var info = spr.CollisionMask; int sprLeft, sprTop, sprRight, sprBottom; // Word of note: There's a lot of copies of nearly the same code here. This is to reduce the number of conditions. int strideFactor = bbox.Top * stride; switch (info.Type) { case MaskType.Rectangle: case MaskType.RectangleWithRotation: if (maskbbox != null) { for (int y = bbox.Top; y <= bbox.Bottom; y++) { for (int x = bbox.Left; x <= bbox.Right; x++) { res.SetTrueReverse(x + strideFactor); if (x < maskbbox.Left) { maskbbox.Left = x; } if (y < maskbbox.Top) { maskbbox.Top = y; } if (x > maskbbox.Right) { maskbbox.Right = x; } if (y > maskbbox.Bottom) { maskbbox.Bottom = y; } } strideFactor += stride; } } else { for (int y = bbox.Top; y <= bbox.Bottom; y++) { for (int x = bbox.Left; x <= bbox.Right; x++) { res.SetTrueReverse(x + strideFactor); } strideFactor += stride; } } break; case MaskType.Precise: case MaskType.PrecisePerFrame: int tolerance = info.AlphaTolerance ?? 0; var data = bmp.BasicLockBits(); unsafe { byte *ptr = (byte *)data.Scan0; if (maskbbox != null) { for (int y = bbox.Top; y <= bbox.Bottom; y++) { for (int x = bbox.Left; x <= bbox.Right; x++) { if (*(ptr + (x * 4) + (y * data.Stride) + 3) > tolerance) { res.SetTrueReverse(x + strideFactor); if (x < maskbbox.Left) { maskbbox.Left = x; } if (y < maskbbox.Top) { maskbbox.Top = y; } if (x > maskbbox.Right) { maskbbox.Right = x; } if (y > maskbbox.Bottom) { maskbbox.Bottom = y; } } } strideFactor += stride; } } else { for (int y = bbox.Top; y <= bbox.Bottom; y++) { for (int x = bbox.Left; x <= bbox.Right; x++) { if (*(ptr + (x * 4) + (y * data.Stride) + 3) > tolerance) { res.SetTrueReverse(x + strideFactor); } } strideFactor += stride; } } } bmp.UnlockBits(data); break; case MaskType.Diamond: { if (info.Mode == MaskMode.FullImage) { sprLeft = 0; sprTop = 0; sprRight = spr.Width - 1; sprBottom = spr.Height - 1; } else { sprLeft = (int)info.Left; sprTop = (int)info.Top; sprRight = (int)info.Right; sprBottom = (int)info.Bottom; } float centerX = (sprLeft + sprRight) / 2; float centerY = (sprTop + sprBottom) / 2; float radiusX = centerX - sprLeft + 0.5f; float radiusY = centerY - sprTop + 0.5f; if (radiusX <= 0 || radiusY <= 0) { break; } if (maskbbox != null) { for (int y = bbox.Top; y <= bbox.Bottom; y++) { for (int x = bbox.Left; x <= bbox.Right; x++) { float normalX = (x - centerX) / radiusX; float normalY = (y - centerY) / radiusY; if (Math.Abs(normalX) + Math.Abs(normalY) <= 1f) { res.SetTrueReverse(x + strideFactor); if (x < maskbbox.Left) { maskbbox.Left = x; } if (y < maskbbox.Top) { maskbbox.Top = y; } if (x > maskbbox.Right) { maskbbox.Right = x; } if (y > maskbbox.Bottom) { maskbbox.Bottom = y; } } } strideFactor += stride; } } else { for (int y = bbox.Top; y <= bbox.Bottom; y++) { for (int x = bbox.Left; x <= bbox.Right; x++) { float normalX = (x - centerX) / radiusX; float normalY = (y - centerY) / radiusY; if (Math.Abs(normalX) + Math.Abs(normalY) <= 1f) { res.SetTrueReverse(x + strideFactor); } } strideFactor += stride; } } break; } case MaskType.Ellipse: { if (info.Mode == MaskMode.FullImage) { sprLeft = 0; sprTop = 0; sprRight = spr.Width - 1; sprBottom = spr.Height - 1; } else { sprLeft = (int)info.Left; sprTop = (int)info.Top; sprRight = (int)info.Right; sprBottom = (int)info.Bottom; } float centerX = (sprLeft + sprRight) / 2; float centerY = (sprTop + sprBottom) / 2; float radiusX = centerX - sprLeft + 0.5f; float radiusY = centerY - sprTop + 0.5f; if (radiusX <= 0 || radiusY <= 0) { break; } if (maskbbox != null) { for (int y = bbox.Top; y <= bbox.Bottom; y++) { for (int x = bbox.Left; x <= bbox.Right; x++) { float normalX = (x - centerX) / radiusX; float normalY = (y - centerY) / radiusY; if (Math.Pow(normalX, 2.0d) + Math.Pow(normalY, 2.0d) <= 1.0d) { res.SetTrueReverse(x + strideFactor); if (x < maskbbox.Left) { maskbbox.Left = x; } if (y < maskbbox.Top) { maskbbox.Top = y; } if (x > maskbbox.Right) { maskbbox.Right = x; } if (y > maskbbox.Bottom) { maskbbox.Bottom = y; } } } strideFactor += stride; } } else { for (int y = bbox.Top; y <= bbox.Bottom; y++) { for (int x = bbox.Left; x <= bbox.Right; x++) { float normalX = (x - centerX) / radiusX; float normalY = (y - centerY) / radiusY; if (Math.Pow(normalX, 2.0d) + Math.Pow(normalY, 2.0d) <= 1.0d) { res.SetTrueReverse(x + strideFactor); } } strideFactor += stride; } } break; } } return(res); }