public unsafe void Render(Surface src, Surface dst, Rectangle[] rois, int start, int len) { int width = src.Width; int height = src.Height; int arrayLens = 1 + this.coarseness; int localStoreSize = arrayLens * 5 * sizeof(int); byte *localStore = stackalloc byte[localStoreSize]; byte *p = localStore; int *intensityCount = (int *)p; p += arrayLens * sizeof(int); uint *avgRed = (uint *)p; p += arrayLens * sizeof(uint); uint *avgGreen = (uint *)p; p += arrayLens * sizeof(uint); uint *avgBlue = (uint *)p; p += arrayLens * sizeof(uint); uint *avgAlpha = (uint *)p; p += arrayLens * sizeof(uint); byte maxIntensity = this.coarseness; //TODO: review here for (int r = start; r < start + len; ++r) { Rectangle rect = rois[r]; int rectTop = rect.Top; int rectBottom = rect.Bottom; int rectLeft = rect.Left; int rectRight = rect.Right; for (int y = rectTop; y < rectBottom; ++y) { ColorBgra *dstPtr = dst.GetPointAddressUnchecked(rect.Left, y); int top = y - brushSize; int bottom = y + brushSize + 1; if (top < 0) { top = 0; } if (bottom > height) { bottom = height; } for (int x = rectLeft; x < rectRight; ++x) { PlatformMemory.SetToZero(localStore, (ulong)localStoreSize); int left = x - brushSize; int right = x + brushSize + 1; if (left < 0) { left = 0; } if (right > width) { right = width; } int numInt = 0; for (int j = top; j < bottom; ++j) { ColorBgra *srcPtr = src.GetPointAddressUnchecked(left, j); for (int i = left; i < right; ++i) { byte intensity = PixelUtils.FastScaleByteByByte(srcPtr->GetIntensityByte(), maxIntensity); ++intensityCount[intensity]; ++numInt; avgRed[intensity] += srcPtr->R; avgGreen[intensity] += srcPtr->G; avgBlue[intensity] += srcPtr->B; avgAlpha[intensity] += srcPtr->A; ++srcPtr; } } byte chosenIntensity = 0; int maxInstance = 0; for (int i = 0; i <= maxIntensity; ++i) { if (intensityCount[i] > maxInstance) { chosenIntensity = (byte)i; maxInstance = intensityCount[i]; } } // TODO: correct handling of alpha values? byte R = (byte)(avgRed[chosenIntensity] / maxInstance); byte G = (byte)(avgGreen[chosenIntensity] / maxInstance); byte B = (byte)(avgBlue[chosenIntensity] / maxInstance); byte A = (byte)(avgAlpha[chosenIntensity] / maxInstance); *dstPtr = ColorBgra.FromBgra(B, G, R, A); ++dstPtr; } } } }
public unsafe override void Apply(ColorBgra *dst, ColorBgra *src, int length) { PlatformMemory.Copy(dst, src, (ulong)length * (ulong)ColorBgra.SizeOf); }
//same as RenderRect, except the histogram is alpha-weighted instead of keeping a separate alpha channel histogram. public unsafe void RenderRectWithAlpha( int rad, Surface src, Surface dst, Rectangle rect) { int width = src.Width; int height = src.Height; int *leadingEdgeX = stackalloc int[rad + 1]; int stride = src.Stride / sizeof(ColorBgra); // approximately (rad + 0.5)^2 int cutoff = ((rad * 2 + 1) * (rad * 2 + 1) + 2) / 4; for (int v = 0; v <= rad; ++v) { for (int u = 0; u <= rad; ++u) { if (u * u + v * v <= cutoff) { leadingEdgeX[v] = u; } } } const int hLength = 256; int * hb = stackalloc int[hLength]; int * hg = stackalloc int[hLength]; int * hr = stackalloc int[hLength]; uint hSize = (uint)(sizeof(int) * hLength); for (int y = rect.Top; y < rect.Bottom; y++) { PlatformMemory.SetToZero(hb, hSize); PlatformMemory.SetToZero(hg, hSize); PlatformMemory.SetToZero(hr, hSize); int area = 0; int sum = 0; ColorBgra *ps = src.GetPointAddressUnchecked(rect.Left, y); ColorBgra *pd = dst.GetPointAddressUnchecked(rect.Left, y); // assert: v + y >= 0 int top = -Math.Min(rad, y); // assert: v + y <= height - 1 int bottom = Math.Min(rad, height - 1 - y); // assert: u + x >= 0 int left = -Math.Min(rad, rect.Left); // assert: u + x <= width - 1 int right = Math.Min(rad, width - 1 - rect.Left); for (int v = top; v <= bottom; ++v) { ColorBgra *psamp = src.GetPointAddressUnchecked(rect.Left + left, y + v); for (int u = left; u <= right; ++u) { byte w = psamp->A; if ((u * u + v * v) <= cutoff) { ++area; sum += w; hb[psamp->B] += w; hg[psamp->G] += w; hr[psamp->R] += w; } ++psamp; } } for (int x = rect.Left; x < rect.Right; x++) { *pd = ApplyWithAlpha(*ps, area, sum, hb, hg, hr); // assert: u + x >= 0 left = -Math.Min(rad, x); // assert: u + x <= width - 1 right = Math.Min(rad + 1, width - 1 - x); // Subtract trailing edge top half int v = -1; while (v >= top) { int u = leadingEdgeX[-v]; if (-u >= left) { break; } --v; } while (v >= top) { int u = leadingEdgeX[-v]; ColorBgra *p = unchecked (ps + (v * stride)) - u; byte w = p->A; hb[p->B] -= w; hg[p->G] -= w; hr[p->R] -= w; sum -= w; --area; --v; } // add leading edge top half v = -1; while (v >= top) { int u = leadingEdgeX[-v]; if (u + 1 <= right) { break; } --v; } while (v >= top) { int u = leadingEdgeX[-v]; ColorBgra *p = unchecked (ps + (v * stride)) + u + 1; byte w = p->A; hb[p->B] += w; hg[p->G] += w; hr[p->R] += w; sum += w; ++area; --v; } // Subtract trailing edge bottom half v = 0; while (v <= bottom) { int u = leadingEdgeX[v]; if (-u >= left) { break; } ++v; } while (v <= bottom) { int u = leadingEdgeX[v]; ColorBgra *p = ps + v * stride - u; byte w = p->A; hb[p->B] -= w; hg[p->G] -= w; hr[p->R] -= w; sum -= w; --area; ++v; } // add leading edge bottom half v = 0; while (v <= bottom) { int u = leadingEdgeX[v]; if (u + 1 <= right) { break; } ++v; } while (v <= bottom) { int u = leadingEdgeX[v]; ColorBgra *p = ps + v * stride + u + 1; byte w = p->A; hb[p->B] += w; hg[p->G] += w; hr[p->R] += w; sum += w; ++area; ++v; } ++ps; ++pd; } } }
internal unsafe static void GetRegionScans(IntPtr hRgn, out Rectangle[] scans, out int area) { uint bytes = 0; int countdown = screwUpMax; int error = 0; // HACK: It seems that sometimes the GetRegionData will return ERROR_INVALID_HANDLE // even though the handle (the HRGN) is fine. Maybe the function is not // re-entrant? I'm not sure, but trying it again seems to fix it. while (countdown > 0) { bytes = SafeNativeMethods.GetRegionData(hRgn, 0, (NativeStructs.RGNDATA *)IntPtr.Zero); error = Marshal.GetLastWin32Error(); if (bytes == 0) { --countdown; System.Threading.Thread.Sleep(5); } else { break; } } // But if we retry several times and it still messes up then we will finally give up. if (bytes == 0) { throw new Win32Exception(error, "GetRegionData returned " + bytes.ToString() + ", GetLastError() = " + error.ToString()); } byte *data; // Up to 512 bytes, allocate on the stack. Otherwise allocate from the heap. if (bytes <= 512) { byte *data1 = stackalloc byte[(int)bytes]; data = data1; } else { data = (byte *)PlatformMemory.Allocate(bytes).ToPointer(); } try { NativeStructs.RGNDATA *pRgnData = (NativeStructs.RGNDATA *)data; uint result = SafeNativeMethods.GetRegionData(hRgn, bytes, pRgnData); if (result != bytes) { throw new OutOfMemoryException("SafeNativeMethods.GetRegionData returned 0"); } NativeStructs.RECT *pRects = NativeStructs.RGNDATA.GetRectsPointer(pRgnData); scans = new Rectangle[pRgnData->rdh.nCount]; area = 0; for (int i = 0; i < scans.Length; ++i) { scans[i] = Rectangle.FromLTRB(pRects[i].left, pRects[i].top, pRects[i].right, pRects[i].bottom); area += scans[i].Width * scans[i].Height; } pRects = null; pRgnData = null; } finally { if (bytes > 512) { PlatformMemory.Free(new IntPtr(data)); } } }
public override void Render(Surface src, Surface dst, Rectangle[] rois, int startIndex, int length) { unsafe { if (this.radius == 0) { for (int ri = startIndex; ri < startIndex + length; ++ri) { dst.CopySurface(src, rois[ri].Location, rois[ri]); } return; } int r = this.radius; int[] w = CreateGaussianBlurRow(r); int wlen = w.Length; int localStoreSize = wlen * 6 * sizeof(long); byte *localStore = stackalloc byte[localStoreSize]; byte *p = localStore; long *waSums = (long *)p; p += wlen * sizeof(long); long *wcSums = (long *)p; p += wlen * sizeof(long); long *aSums = (long *)p; p += wlen * sizeof(long); long *bSums = (long *)p; p += wlen * sizeof(long); long *gSums = (long *)p; p += wlen * sizeof(long); long *rSums = (long *)p; p += wlen * sizeof(long); ulong arraysLength = (ulong)(sizeof(long) * wlen); for (int ri = startIndex; ri < startIndex + length; ++ri) { Rectangle rect = rois[ri]; if (rect.Height >= 1 && rect.Width >= 1) { for (int y = rect.Top; y < rect.Bottom; ++y) { PlatformMemory.SetToZero(localStore, (ulong)localStoreSize); long waSum = 0; long wcSum = 0; long aSum = 0; long bSum = 0; long gSum = 0; long rSum = 0; ColorBgra *dstPtr = dst.GetPointAddressUnchecked(rect.Left, y); for (int wx = 0; wx < wlen; ++wx) { int srcX = rect.Left + wx - r; waSums[wx] = 0; wcSums[wx] = 0; aSums[wx] = 0; bSums[wx] = 0; gSums[wx] = 0; rSums[wx] = 0; if (srcX >= 0 && srcX < src.Width) { for (int wy = 0; wy < wlen; ++wy) { int srcY = y + wy - r; if (srcY >= 0 && srcY < src.Height) { ColorBgra c = src.GetPointUnchecked(srcX, srcY); int wp = w[wy]; waSums[wx] += wp; wp *= c.A + (c.A >> 7); wcSums[wx] += wp; wp >>= 8; aSums[wx] += wp * c.A; bSums[wx] += wp * c.B; gSums[wx] += wp * c.G; rSums[wx] += wp * c.R; } } int wwx = w[wx]; waSum += wwx * waSums[wx]; wcSum += wwx * wcSums[wx]; aSum += wwx * aSums[wx]; bSum += wwx * bSums[wx]; gSum += wwx * gSums[wx]; rSum += wwx * rSums[wx]; } } wcSum >>= 8; if (waSum == 0 || wcSum == 0) { dstPtr->Bgra = 0; } else { int alpha = (int)(aSum / waSum); int blue = (int)(bSum / wcSum); int green = (int)(gSum / wcSum); int red = (int)(rSum / wcSum); dstPtr->Bgra = ColorBgra.BgraToUInt32(blue, green, red, alpha); } ++dstPtr; for (int x = rect.Left + 1; x < rect.Right; ++x) { for (int i = 0; i < wlen - 1; ++i) { waSums[i] = waSums[i + 1]; wcSums[i] = wcSums[i + 1]; aSums[i] = aSums[i + 1]; bSums[i] = bSums[i + 1]; gSums[i] = gSums[i + 1]; rSums[i] = rSums[i + 1]; } waSum = 0; wcSum = 0; aSum = 0; bSum = 0; gSum = 0; rSum = 0; int wx; for (wx = 0; wx < wlen - 1; ++wx) { long wwx = (long)w[wx]; waSum += wwx * waSums[wx]; wcSum += wwx * wcSums[wx]; aSum += wwx * aSums[wx]; bSum += wwx * bSums[wx]; gSum += wwx * gSums[wx]; rSum += wwx * rSums[wx]; } wx = wlen - 1; waSums[wx] = 0; wcSums[wx] = 0; aSums[wx] = 0; bSums[wx] = 0; gSums[wx] = 0; rSums[wx] = 0; int srcX = x + wx - r; if (srcX >= 0 && srcX < src.Width) { for (int wy = 0; wy < wlen; ++wy) { int srcY = y + wy - r; if (srcY >= 0 && srcY < src.Height) { ColorBgra c = src.GetPointUnchecked(srcX, srcY); int wp = w[wy]; waSums[wx] += wp; wp *= c.A + (c.A >> 7); wcSums[wx] += wp; wp >>= 8; aSums[wx] += wp * (long)c.A; bSums[wx] += wp * (long)c.B; gSums[wx] += wp * (long)c.G; rSums[wx] += wp * (long)c.R; } } int wr = w[wx]; waSum += (long)wr * waSums[wx]; wcSum += (long)wr * wcSums[wx]; aSum += (long)wr * aSums[wx]; bSum += (long)wr * bSums[wx]; gSum += (long)wr * gSums[wx]; rSum += (long)wr * rSums[wx]; } wcSum >>= 8; if (waSum == 0 || wcSum == 0) { dstPtr->Bgra = 0; } else { int alpha = (int)(aSum / waSum); int blue = (int)(bSum / wcSum); int green = (int)(gSum / wcSum); int red = (int)(rSum / wcSum); dstPtr->Bgra = ColorBgra.BgraToUInt32(blue, green, red, alpha); } ++dstPtr; } } } } } }
public static void SetPlatformMemImpl(PlatformMemory p) { platformMem = p; }