unsafe public override void Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois) { int w = dst.Width; int h = dst.Height; double invH = 1.0 / h; double zoom = 1 + zoomFactor * Data.Zoom; double invZoom = 1.0 / zoom; double invQuality = 1.0 / (double)Data.Quality; int count = Data.Quality * Data.Quality + 1; double invCount = 1.0 / (double)count; double angleTheta = (Data.Angle * 2 * Math.PI) / 360; ColorBgra *dst_dataptr = (ColorBgra *)dst.DataPtr; int dst_width = dst.Width; foreach (Gdk.Rectangle rect in rois) { for (int y = rect.Top; y <= rect.GetBottom(); y++) { ColorBgra *dstPtr = dst.GetPointAddressUnchecked(dst_dataptr, dst_width, rect.Left, y); for (int x = rect.Left; x <= rect.GetRight(); x++) { int r = 0; int g = 0; int b = 0; int a = 0; for (double i = 0; i < count; i++) { double u = (2.0 * x - w + (i * invCount)) * invH; double v = (2.0 * y - h + ((i * invQuality) % 1)) * invH; double radius = Math.Sqrt((u * u) + (v * v)); double radiusP = radius; double theta = Math.Atan2(v, u); double thetaP = theta + angleTheta; double uP = radiusP * Math.Cos(thetaP); double vP = radiusP * Math.Sin(thetaP); double m = Mandelbrot((uP * invZoom) + this.xOffset, (vP * invZoom) + this.yOffset, Data.Factor); double c = 64 + Data.Factor * m; r += Utility.ClampToByte(c - 768); g += Utility.ClampToByte(c - 512); b += Utility.ClampToByte(c - 256); a += Utility.ClampToByte(c - 0); } *dstPtr = ColorBgra.FromBgra(Utility.ClampToByte(b / count), Utility.ClampToByte(g / count), Utility.ClampToByte(r / count), Utility.ClampToByte(a / count)); ++dstPtr; } } if (Data.InvertColors) { for (int y = rect.Top; y <= rect.GetBottom(); y++) { ColorBgra *dstPtr = dst.GetPointAddressUnchecked(dst_dataptr, dst_width, rect.Left, y); for (int x = rect.Left; x <= rect.GetRight(); ++x) { ColorBgra c = *dstPtr; c.B = (byte)(255 - c.B); c.G = (byte)(255 - c.G); c.R = (byte)(255 - c.R); *dstPtr = c; ++dstPtr; } } } } }
public unsafe void RenderRect( int rad, ImageSurface src, ImageSurface dst, Gdk.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]; int * ha = stackalloc int[hLength]; uint hSize = (uint)(sizeof(int) * hLength); for (int y = rect.Top; y < rect.Bottom; y++) { SetToZero(hb, hSize); SetToZero(hg, hSize); SetToZero(hr, hSize); SetToZero(ha, hSize); int area = 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) { if ((u * u + v * v) <= cutoff) { ++area; ++hb[psamp->B]; ++hg[psamp->G]; ++hr[psamp->R]; ++ha[psamp->A]; } ++psamp; } } for (int x = rect.Left; x < rect.Right; x++) { *pd = Apply(*ps, area, hb, hg, hr, ha); // 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; --hb[p->B]; --hg[p->G]; --hr[p->R]; --ha[p->A]; --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; ++hb[p->B]; ++hg[p->G]; ++hr[p->R]; ++ha[p->A]; ++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; --hb[p->B]; --hg[p->G]; --hr[p->R]; --ha[p->A]; --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; ++hb[p->B]; ++hg[p->G]; ++hr[p->R]; ++ha[p->A]; ++area; ++v; } ++ps; ++pd; } } }
public static unsafe ColorBgra GetBilinearSampleClamped(this ImageSurface src, ColorBgra *srcDataPtr, int srcWidth, int srcHeight, float x, float y) { if (!Utility.IsNumber(x) || !Utility.IsNumber(y)) { return(ColorBgra.Transparent); } float u = x; float v = y; if (u < 0) { u = 0; } else if (u > srcWidth - 1) { u = srcWidth - 1; } if (v < 0) { v = 0; } else if (v > srcHeight - 1) { v = srcHeight - 1; } unchecked { int iu = (int)Math.Floor(u); uint sxfrac = (uint)(256 * (u - (float)iu)); uint sxfracinv = 256 - sxfrac; int iv = (int)Math.Floor(v); uint syfrac = (uint)(256 * (v - (float)iv)); uint syfracinv = 256 - syfrac; uint wul = (uint)(sxfracinv * syfracinv); uint wur = (uint)(sxfrac * syfracinv); uint wll = (uint)(sxfracinv * syfrac); uint wlr = (uint)(sxfrac * syfrac); int sx = iu; int sy = iv; int sleft = sx; int sright; if (sleft == (srcWidth - 1)) { sright = sleft; } else { sright = sleft + 1; } int stop = sy; int sbottom; if (stop == (srcHeight - 1)) { sbottom = stop; } else { sbottom = stop + 1; } ColorBgra *cul = src.GetPointAddressUnchecked(srcDataPtr, srcWidth, sleft, stop); ColorBgra *cur = cul + (sright - sleft); ColorBgra *cll = src.GetPointAddressUnchecked(srcDataPtr, srcWidth, sleft, sbottom); ColorBgra *clr = cll + (sright - sleft); ColorBgra c = ColorBgra.BlendColors4W16IP(*cul, wul, *cur, wur, *cll, wll, *clr, wlr); return(c); } }
public unsafe override void Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois) { var selection = PintaCore.LivePreview.RenderBounds; this.defaultRadius = Math.Min(selection.Width, selection.Height) * 0.5; this.defaultRadius2 = this.defaultRadius * this.defaultRadius; var x_center_offset = selection.Left + (selection.Width * (1.0 + Data.CenterOffset.X) * 0.5); var y_center_offset = selection.Top + (selection.Height * (1.0 + Data.CenterOffset.Y) * 0.5); ColorBgra colPrimary = PintaCore.Palette.PrimaryColor.ToColorBgra(); ColorBgra colSecondary = PintaCore.Palette.SecondaryColor.ToColorBgra(); ColorBgra colTransparent = ColorBgra.Transparent; int aaSampleCount = Data.Quality * Data.Quality; Cairo.PointD *aaPoints = stackalloc Cairo.PointD[aaSampleCount]; Utility.GetRgssOffsets(aaPoints, aaSampleCount, Data.Quality); ColorBgra *samples = stackalloc ColorBgra[aaSampleCount]; TransformData td; foreach (Gdk.Rectangle rect in rois) { for (int y = rect.Top; y <= rect.GetBottom(); y++) { ColorBgra *dstPtr = dst.GetPointAddressUnchecked(rect.Left, y); double relativeY = y - y_center_offset; for (int x = rect.Left; x <= rect.GetRight(); x++) { double relativeX = x - x_center_offset; int sampleCount = 0; for (int p = 0; p < aaSampleCount; ++p) { td.X = relativeX + aaPoints[p].X; td.Y = relativeY - aaPoints[p].Y; InverseTransform(ref td); float sampleX = (float)(td.X + x_center_offset); float sampleY = (float)(td.Y + y_center_offset); ColorBgra sample = colPrimary; if (IsOnSurface(src, sampleX, sampleY)) { sample = src.GetBilinearSample(sampleX, sampleY); } else { switch (Data.EdgeBehavior) { case WarpEdgeBehavior.Clamp: sample = src.GetBilinearSampleClamped(sampleX, sampleY); break; case WarpEdgeBehavior.Wrap: sample = src.GetBilinearSampleWrapped(sampleX, sampleY); break; case WarpEdgeBehavior.Reflect: sample = src.GetBilinearSampleClamped(ReflectCoord(sampleX, src.Width), ReflectCoord(sampleY, src.Height)); break; case WarpEdgeBehavior.Primary: sample = colPrimary; break; case WarpEdgeBehavior.Secondary: sample = colSecondary; break; case WarpEdgeBehavior.Transparent: sample = colTransparent; break; case WarpEdgeBehavior.Original: sample = src.GetColorBgraUnchecked(x, y); break; default: break; } } samples[sampleCount] = sample; ++sampleCount; } *dstPtr = ColorBgra.Blend(samples, sampleCount); ++dstPtr; } } } }
protected override unsafe Gdk.Rectangle OnMouseMove(Context g, Color strokeColor, ImageSurface surface, int x, int y, int lastX, int lastY) { int rad = (int)(g.LineWidth / 2.0 + 0.5); rad /= 2; rad *= 2; if (rad < 2) { rad = 2; } //Initialize lookup table when first used (to prevent slower startup of the application) if (lut_factor == null) { lut_factor = new byte[LUT_Resolution + 1, LUT_Resolution + 1]; for (int dy = 0; dy < LUT_Resolution + 1; dy++) { for (int dx = 0; dx < LUT_Resolution + 1; dx++) { double d = Math.Sqrt(dx * dx + dy * dy) / LUT_Resolution; if (d > 1.0) { lut_factor [dx, dy] = 0; } else { lut_factor [dx, dy] = (byte)(Math.Cos(Math.Sqrt(d) * Math.PI / 2.0) * 255.0); } } } } Gdk.Rectangle surface_rect = new Gdk.Rectangle(0, 0, surface.Width, surface.Height); Gdk.Rectangle brush_rect = new Gdk.Rectangle(x - rad, y - rad, 2 * rad, 2 * rad); Gdk.Rectangle dest_rect = Gdk.Rectangle.Intersect(surface_rect, brush_rect); if ((dest_rect.Width > 1) && (dest_rect.Height > 1)) { //Allow Clipping through a temporary surface ImageSurface tmp_surface = new ImageSurface(Format.Argb32, dest_rect.Width, dest_rect.Height); using (Context g2 = new Context(tmp_surface)) { g2.Operator = Operator.Source; g2.SetSourceSurface(surface, -dest_rect.Left, -dest_rect.Top); g2.Rectangle(new Rectangle(0, 0, dest_rect.Width, dest_rect.Height)); g2.Fill(); } //Flush to make sure all drawing operations are finished tmp_surface.Flush(); int[,] mean_r = new int[dest_rect.Width / 2 + 1, dest_rect.Height / 2 + 1]; int[,] mean_g = new int[dest_rect.Width / 2 + 1, dest_rect.Height / 2 + 1]; int[,] mean_b = new int[dest_rect.Width / 2 + 1, dest_rect.Height / 2 + 1]; int[,] mean_a = new int[dest_rect.Width / 2 + 1, dest_rect.Height / 2 + 1]; int[,] mean_c = new int[dest_rect.Width / 2 + 1, dest_rect.Height / 2 + 1]; for (int iy = 0; iy < dest_rect.Height / 2; iy++) { for (int ix = 0; ix < dest_rect.Width / 2; ix++) { mean_a[ix, iy] = 0; mean_r[ix, iy] = 0; mean_g[ix, iy] = 0; mean_b[ix, iy] = 0; mean_c[ix, iy] = 0; } } for (int iy = 0; iy < dest_rect.Height; iy++) { ColorBgra *srcRowPtr = tmp_surface.GetPointAddressUnchecked(0, iy); for (int ix = 0; ix < dest_rect.Width; ix++) { ColorBgra col = (*srcRowPtr).ToStraightAlpha(); int pos_x = ix >> 1, pos_y = iy >> 1; mean_r[pos_x, pos_y] += col.R; mean_g[pos_x, pos_y] += col.G; mean_b[pos_x, pos_y] += col.B; mean_a[pos_x, pos_y] += col.A; mean_c[pos_x, pos_y]++; srcRowPtr++; } } for (int iy = 0; iy < dest_rect.Height; iy++) { ColorBgra *dstRowPtr = tmp_surface.GetPointAddressUnchecked(0, iy); int dy = ((iy + dest_rect.Top - y) * LUT_Resolution) / rad; if (dy < 0) { dy = -dy; } for (int ix = 0; ix < dest_rect.Width; ix++) { ColorBgra col = (*dstRowPtr).ToStraightAlpha(); int dx = ((ix + dest_rect.Left - x) * LUT_Resolution) / rad; if (dx < 0) { dx = -dx; } int factor = lut_factor[dx, dy]; int pos_x = ix >> 1, pos_y = iy >> 1; int count = mean_c[pos_x, pos_y]; int red = col.R + (col.R - mean_r[pos_x, pos_y] / count); int green = col.G + (col.G - mean_g[pos_x, pos_y] / count); int blue = col.B + (col.B - mean_b[pos_x, pos_y] / count); int alpha = col.A + (col.A - mean_a[pos_x, pos_y] / count); /* * int diff_red = (4*red - tmp[ix-1,iy].R - tmp[ix,iy-1].R - tmp[ix+1,iy].R - tmp[ix,iy+1].R)/4; * int diff_green = (4*green - tmp[ix-1,iy].G - tmp[ix,iy-1].G - tmp[ix+1,iy].G - tmp[ix,iy+1].G)/4; * int diff_blue = (4*blue - tmp[ix-1,iy].B - tmp[ix,iy-1].B - tmp[ix+1,iy].B - tmp[ix,iy+1].B)/4; * int diff_alpha = (4*alpha - tmp[ix-1,iy].A - tmp[ix,iy-1].A - tmp[ix+1,iy].A - tmp[ix,iy+1].A)/4; */ //red -= diff_red; //if ((red & 255) != 0) { //Negative or grater than 255 if (red > 255) { red = 255; } if (red < 0) { red = 0; } //} //green -= diff_green; //if ((green & 255) != 0) { //Negative or grater than 255 if (green > 255) { green = 255; } if (green < 0) { green = 0; } //} //blue -= diff_blue; //if ((blue & 255) != 0) { //Negative or grater than 255 if (blue > 255) { blue = 255; } if (blue < 0) { blue = 0; } //} //alpha -= diff_alpha; //if ((alpha & 255) != 0) { //Negative or grater than 255 if (alpha > 255) { alpha = 255; } if (alpha < 0) { alpha = 0; } col.R = (byte)((red * factor + col.R * (512 - factor)) >> 9); col.G = (byte)((green * factor + col.G * (512 - factor)) >> 9); col.B = (byte)((blue * factor + col.B * (512 - factor)) >> 9); col.A = (byte)((alpha * factor + col.A * (512 - factor)) >> 9); *dstRowPtr = col.ToPremultipliedAlpha(); dstRowPtr++; } } //Draw the final result on the surface g.Operator = Operator.Source; g.SetSourceSurface(tmp_surface, dest_rect.Left, dest_rect.Top); g.Rectangle(new Rectangle(dest_rect.Left, dest_rect.Top, dest_rect.Width, dest_rect.Height)); g.Fill(); } return(Gdk.Rectangle.Zero); }
unsafe public static void RenderBlurEffect(ImageSurface src, ImageSurface dest, Gdk.Rectangle[] rois, int radius) { int r = 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); // Cache these for a massive performance boost int src_width = src.Width; int src_height = src.Height; var src_data_ptr = (ColorBgra *)src.DataPtr; foreach (Gdk.Rectangle rect in rois) { if (rect.Height >= 1 && rect.Width >= 1) { for (int y = rect.Top; y < rect.Bottom; ++y) { //Memory.SetToZero (localStore, (ulong)localStoreSize); long waSum = 0; long wcSum = 0; long aSum = 0; long bSum = 0; long gSum = 0; long rSum = 0; ColorBgra *dstPtr = dest.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) { var c = src.GetPointUnchecked(src_data_ptr, src_width, 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 = 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) { var c = src.GetPointUnchecked(src_data_ptr, src_width, 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 += wr * waSums[wx]; wcSum += wr * wcSums[wx]; aSum += wr * aSums[wx]; bSum += wr * bSums[wx]; gSum += wr * gSums[wx]; rSum += 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 unsafe override void Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois) { this.intensity = Data.Intensity; this.colorSaturation = Data.ColorSaturation; this.coverage = 0.01 * Data.Coverage; int dev = this.intensity * this.intensity / 4; int sat = this.colorSaturation * 4096 / 100; if (threadRand == null) { threadRand = new Random(unchecked (System.Threading.Thread.CurrentThread.GetHashCode() ^ unchecked ((int)DateTime.Now.Ticks))); } Random localRand = threadRand; int[] localLookup = lookup; foreach (Gdk.Rectangle rect in rois) { for (int y = rect.Top; y < rect.Bottom; ++y) { ColorBgra *srcPtr = src.GetPointAddressUnchecked(rect.Left, y); ColorBgra *dstPtr = dst.GetPointAddressUnchecked(rect.Left, y); for (int x = 0; x < rect.Width; ++x) { if (localRand.NextDouble() > this.coverage) { *dstPtr = *srcPtr; } else { int r; int g; int b; int i; r = localLookup[localRand.Next(tableSize)]; g = localLookup[localRand.Next(tableSize)]; b = localLookup[localRand.Next(tableSize)]; i = (4899 * r + 9618 * g + 1867 * b) >> 14; r = i + (((r - i) * sat) >> 12); g = i + (((g - i) * sat) >> 12); b = i + (((b - i) * sat) >> 12); dstPtr->R = Utility.ClampToByte(srcPtr->R + ((r * dev + 32768) >> 16)); dstPtr->G = Utility.ClampToByte(srcPtr->G + ((g * dev + 32768) >> 16)); dstPtr->B = Utility.ClampToByte(srcPtr->B + ((b * dev + 32768) >> 16)); dstPtr->A = srcPtr->A; } ++srcPtr; ++dstPtr; } } } }
unsafe public override void Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois) { int width = dst.Width; int height = dst.Height; float hw = width / 2f; float hh = height / 2f; float sin = (float)Math.Sin(Data.Rotation * Math.PI / 180.0); float cos = (float)Math.Cos(Data.Rotation * Math.PI / 180.0); float scale = (float)Math.PI / Data.TileSize; float intensity = Data.Intensity; intensity = intensity * intensity / 10 * Math.Sign(intensity); int aaLevel = 4; int aaSamples = aaLevel * aaLevel + 1; PointD *aaPoints = stackalloc PointD[aaSamples]; for (int i = 0; i < aaSamples; ++i) { double x = (i * aaLevel) / (double)aaSamples; double y = i / (double)aaSamples; x -= (int)x; // RGSS + rotation to maximize AA quality aaPoints[i] = new PointD((double)(cos * x + sin * y), (double)(cos * y - sin * x)); } int src_width = src.Width; ColorBgra *src_data_ptr = (ColorBgra *)src.DataPtr; foreach (var rect in rois) { for (int y = rect.Top; y <= rect.GetBottom(); y++) { float j = y - hh; ColorBgra *dstPtr = dst.GetPointAddressUnchecked(rect.Left, y); for (int x = rect.Left; x <= rect.GetRight(); x++) { int b = 0; int g = 0; int r = 0; int a = 0; float i = x - hw; for (int p = 0; p < aaSamples; ++p) { PointD pt = aaPoints[p]; float u = i + (float)pt.X; float v = j - (float)pt.Y; float s = cos * u + sin * v; float t = -sin * u + cos * v; s += intensity * (float)Math.Tan(s * scale); t += intensity * (float)Math.Tan(t * scale); u = cos * s - sin * t; v = sin * s + cos * t; int xSample = (int)(hw + u); int ySample = (int)(hh + v); xSample = (xSample + width) % width; // This makes it a little faster if (xSample < 0) { xSample = (xSample + width) % width; } ySample = (ySample + height) % height; // This makes it a little faster if (ySample < 0) { ySample = (ySample + height) % height; } ColorBgra sample = *src.GetPointAddressUnchecked(src_data_ptr, src_width, xSample, ySample); b += sample.B; g += sample.G; r += sample.R; a += sample.A; } *(dstPtr++) = ColorBgra.FromBgra((byte)(b / aaSamples), (byte)(g / aaSamples), (byte)(r / aaSamples), (byte)(a / aaSamples)); } } } }
protected unsafe override void OnMouseMove(object o, Gtk.MotionNotifyEventArgs args, Cairo.PointD point) { Document doc = PintaCore.Workspace.ActiveDocument; ColorBgra old_color; ColorBgra new_color; if (mouse_button == 1) { old_color = PintaCore.Palette.PrimaryColor.ToColorBgra(); new_color = PintaCore.Palette.SecondaryColor.ToColorBgra(); } else if (mouse_button == 3) { old_color = PintaCore.Palette.SecondaryColor.ToColorBgra(); new_color = PintaCore.Palette.PrimaryColor.ToColorBgra(); } else { last_point = point_empty; return; } int x = (int)point.X; int y = (int)point.Y; if (last_point.Equals(point_empty)) { last_point = new Point(x, y); } if (doc.Workspace.PointInCanvas(point)) { surface_modified = true; } ImageSurface surf = doc.CurrentUserLayer.Surface; ImageSurface tmp_layer = doc.ToolLayer.Surface; Gdk.Rectangle roi = GetRectangleFromPoints(last_point, new Point(x, y)); roi = PintaCore.Workspace.ClampToImageSize(roi); myTolerance = (int)(Tolerance * 256); tmp_layer.Flush(); ColorBgra *tmp_data_ptr = (ColorBgra *)tmp_layer.DataPtr; int tmp_width = tmp_layer.Width; ColorBgra *surf_data_ptr = (ColorBgra *)surf.DataPtr; int surf_width = surf.Width; // The stencil lets us know if we've already checked this // pixel, providing a nice perf boost // Maybe this should be changed to a BitVector2DSurfaceAdapter? for (int i = roi.X; i <= roi.GetRight(); i++) { for (int j = roi.Y; j <= roi.GetBottom(); j++) { if (stencil[i, j]) { continue; } if (IsColorInTolerance(new_color, surf.GetColorBgra(surf_data_ptr, surf_width, i, j))) { *tmp_layer.GetPointAddressUnchecked(tmp_data_ptr, tmp_width, i, j) = AdjustColorDifference(new_color, old_color, surf.GetColorBgra(surf_data_ptr, surf_width, i, j)); } stencil[i, j] = true; } } tmp_layer.MarkDirty(); using (Context g = new Context(surf)) { g.AppendPath(doc.Selection.SelectionPath); g.FillRule = FillRule.EvenOdd; g.Clip(); g.Antialias = UseAntialiasing ? Antialias.Subpixel : Antialias.None; g.MoveTo(last_point.X, last_point.Y); g.LineTo(x, y); g.LineWidth = BrushWidth; g.LineJoin = LineJoin.Round; g.LineCap = LineCap.Round; g.SetSource(tmp_layer); g.Stroke(); } doc.Workspace.Invalidate(roi); last_point = new Point(x, y); }
protected override unsafe Gdk.Rectangle OnMouseMove(Context g, Color strokeColor, ImageSurface surface, int x, int y, int lastX, int lastY) { int rad = (int)(g.LineWidth / 2.0) + 1; int stroke_a = (int)(255.0 * strokeColor.A); int stroke_r = (int)(255.0 * strokeColor.R); int stroke_g = (int)(255.0 * strokeColor.G); int stroke_b = (int)(255.0 * strokeColor.B); Gdk.Rectangle surface_rect = new Gdk.Rectangle(0, 0, surface.Width, surface.Height); Gdk.Rectangle brush_rect = new Gdk.Rectangle(x - rad, y - rad, 2 * rad, 2 * rad); Gdk.Rectangle dest_rect = Gdk.Rectangle.Intersect(surface_rect, brush_rect); //Initialize lookup table when first used (to prevent slower startup of the application) if (lut_factor == null) { lut_factor = new byte[LUT_Resolution + 1, LUT_Resolution + 1]; for (int dy = 0; dy < LUT_Resolution + 1; dy++) { for (int dx = 0; dx < LUT_Resolution + 1; dx++) { double d = Math.Sqrt(dx * dx + dy * dy) / LUT_Resolution; if (d > 1.0) { lut_factor [dx, dy] = 0; } else { lut_factor [dx, dy] = (byte)(Math.Cos(Math.Sqrt(d) * Math.PI / 2.0) * 255); } } } } if ((dest_rect.Width > 0) && (dest_rect.Height > 0)) { //Allow Clipping through a temporary surface ImageSurface tmp_surface = new ImageSurface(Format.Argb32, dest_rect.Width, dest_rect.Height); using (Context g2 = new Context(tmp_surface)) { g2.Operator = Operator.Source; g2.SetSourceSurface(surface, -dest_rect.Left, -dest_rect.Top); g2.Rectangle(new Rectangle(0, 0, dest_rect.Width, dest_rect.Height)); g2.Fill(); } //Flush to make sure all drawing operations are finished tmp_surface.Flush(); for (int iy = dest_rect.Top; iy < dest_rect.Bottom; iy++) { ColorBgra *srcRowPtr = tmp_surface.GetPointAddressUnchecked(0, iy - dest_rect.Top); int dy = ((iy - y) * LUT_Resolution) / rad; if (dy < 0) { dy = -dy; } for (int ix = dest_rect.Left; ix < dest_rect.Right; ix++) { ColorBgra col = (*srcRowPtr).ToStraightAlpha(); int dx = ((ix - x) * LUT_Resolution) / rad; if (dx < 0) { dx = -dx; } int force = lut_factor[dx, dy]; col.A = (byte)((col.A * (255 - force) + stroke_a * force) / 255); col.R = (byte)((col.R * (255 - force) + stroke_r * force) / 255); col.G = (byte)((col.G * (255 - force) + stroke_g * force) / 255); col.B = (byte)((col.B * (255 - force) + stroke_b * force) / 255); *srcRowPtr = col.ToPremultipliedAlpha(); srcRowPtr++; } } //Draw the final result on the surface g.Operator = Operator.Source; g.SetSourceSurface(tmp_surface, dest_rect.Left, dest_rect.Top); g.Rectangle(new Rectangle(dest_rect.Left, dest_rect.Top, dest_rect.Width, dest_rect.Height)); g.Fill(); } return(Gdk.Rectangle.Zero); }
public unsafe override void Render(ImageSurface src, ImageSurface dest, Gdk.Rectangle[] rois) { int width = src.Width; int height = src.Height; int arrayLens = 1 + Data.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 = (byte)Data.Coarseness; foreach (Gdk.Rectangle rect in rois) { int rectTop = rect.Top; int rectBottom = rect.GetBottom(); int rectLeft = rect.Left; int rectRight = rect.GetRight(); ColorBgra *dst_dataptr = (ColorBgra *)dest.DataPtr; int dst_width = dest.Width; ColorBgra *src_dataptr = (ColorBgra *)src.DataPtr; int src_width = src.Width; for (int y = rectTop; y <= rectBottom; ++y) { ColorBgra *dstPtr = dest.GetPointAddressUnchecked(dst_dataptr, dst_width, rect.Left, y); int top = y - Data.BrushSize; int bottom = y + Data.BrushSize + 1; if (top < 0) { top = 0; } if (bottom > height) { bottom = height; } for (int x = rectLeft; x <= rectRight; ++x) { SetToZero(localStore, (ulong)localStoreSize); int left = x - Data.BrushSize; int right = x + Data.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(src_dataptr, src_width, left, j); for (int i = left; i < right; ++i) { byte intensity = Utility.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 Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois) { if (Data.Angle == 0) { // Copy src to dest return; } int w = dst.Width; int h = dst.Height; int fcx = (w << 15) + (int)(Data.Offset.X * (w << 15)); int fcy = (h << 15) + (int)(Data.Offset.Y * (h << 15)); int n = (Data.Quality * Data.Quality) * (30 + Data.Quality * Data.Quality); int fr = (int)(Data.Angle * Math.PI * 65536.0 / 181.0); foreach (Gdk.Rectangle rect in rois) { for (int y = rect.Top; y <= rect.GetBottom(); ++y) { ColorBgra *dstPtr = dst.GetPointAddressUnchecked(rect.Left, y); ColorBgra *srcPtr = src.GetPointAddressUnchecked(rect.Left, y); for (int x = rect.Left; x <= rect.GetRight(); ++x) { int fx = (x << 16) - fcx; int fy = (y << 16) - fcy; int fsr = fr / n; int sr = 0; int sg = 0; int sb = 0; int sa = 0; int sc = 0; sr += srcPtr->R * srcPtr->A; sg += srcPtr->G * srcPtr->A; sb += srcPtr->B * srcPtr->A; sa += srcPtr->A; ++sc; int ox1 = fx; int ox2 = fx; int oy1 = fy; int oy2 = fy; ColorBgra *src_dataptr = (ColorBgra *)src.DataPtr; int src_width = src.Width; for (int i = 0; i < n; ++i) { Rotate(ref ox1, ref oy1, fsr); Rotate(ref ox2, ref oy2, -fsr); int u1 = ox1 + fcx + 32768 >> 16; int v1 = oy1 + fcy + 32768 >> 16; if (u1 > 0 && v1 > 0 && u1 < w && v1 < h) { ColorBgra *sample = src.GetPointAddressUnchecked(src_dataptr, src_width, u1, v1); sr += sample->R * sample->A; sg += sample->G * sample->A; sb += sample->B * sample->A; sa += sample->A; ++sc; } int u2 = ox2 + fcx + 32768 >> 16; int v2 = oy2 + fcy + 32768 >> 16; if (u2 > 0 && v2 > 0 && u2 < w && v2 < h) { ColorBgra *sample = src.GetPointAddressUnchecked(src_dataptr, src_width, u2, v2); sr += sample->R * sample->A; sg += sample->G * sample->A; sb += sample->B * sample->A; sa += sample->A; ++sc; } } if (sa > 0) { *dstPtr = ColorBgra.FromBgra( Utility.ClampToByte(sb / sa), Utility.ClampToByte(sg / sa), Utility.ClampToByte(sr / sa), Utility.ClampToByte(sa / sc)); } else { dstPtr->Bgra = 0; } ++dstPtr; ++srcPtr; } } } }
public unsafe override void Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois) { PointD start = new PointD(0, 0); double theta = ((double)(Data.Angle + 180) * 2 * Math.PI) / 360.0; double alpha = (double)Data.Distance; PointD end = new PointD((float)alpha * Math.Cos(theta), (float)(-alpha * Math.Sin(theta))); if (Data.Centered) { start.X = -end.X / 2.0f; start.Y = -end.Y / 2.0f; end.X /= 2.0f; end.Y /= 2.0f; } PointD[] points = new PointD[((1 + Data.Distance) * 3) / 2]; if (points.Length == 1) { points[0] = new PointD(0, 0); } else { for (int i = 0; i < points.Length; ++i) { float frac = (float)i / (float)(points.Length - 1); points[i] = Utility.Lerp(start, end, frac); } } ColorBgra *samples = stackalloc ColorBgra[points.Length]; ColorBgra *src_dataptr = (ColorBgra *)src.DataPtr; int src_width = src.Width; int src_height = src.Height; foreach (Gdk.Rectangle rect in rois) { for (int y = rect.Top; y <= rect.GetBottom(); ++y) { ColorBgra *dstPtr = dst.GetPointAddressUnchecked(rect.Left, y); for (int x = rect.Left; x <= rect.GetRight(); ++x) { int sampleCount = 0; for (int j = 0; j < points.Length; ++j) { PointD pt = new PointD(points[j].X + (float)x, points[j].Y + (float)y); if (pt.X >= 0 && pt.Y >= 0 && pt.X <= (src_width - 1) && pt.Y <= (src_height - 1)) { samples[sampleCount] = src.GetBilinearSample(src_dataptr, src_width, src_height, (float)pt.X, (float)pt.Y); ++sampleCount; } } *dstPtr = ColorBgra.Blend(samples, sampleCount); ++dstPtr; } } } }