private void CreateBitmapContexts(Data data) { m_bitmapContexts = new BitmapContext[data.bitmaps.Length]; for (int i = 0; i < data.bitmaps.Length; ++i) { Format.Bitmap bitmap = data.bitmaps[i]; // Ignore null texture if (bitmap.textureFragmentId == -1) continue; int bitmapExId = -i - 1; Format.BitmapEx bitmapEx = new Format.BitmapEx(); bitmapEx.matrixId = bitmap.matrixId; bitmapEx.textureFragmentId = bitmap.textureFragmentId; bitmapEx.u = 0; bitmapEx.v = 0; bitmapEx.w = 1; bitmapEx.h = 1; m_bitmapContexts[i] = new BitmapContext(this, data, bitmapEx, bitmapExId); } m_bitmapExContexts = new BitmapContext[data.bitmapExs.Length]; for (int i = 0; i < data.bitmapExs.Length; ++i) { Format.BitmapEx bitmapEx = data.bitmapExs[i]; // Ignore null texture if (bitmapEx.textureFragmentId == -1) continue; m_bitmapExContexts[i] = new BitmapContext(this, data, bitmapEx, i); } }
public static IEnumerable<Color> GetMostPopularColors(BitmapContext context, int k) { try { unsafe { Dictionary<Color, int> colorsDictionary = new Dictionary<Color, int>(); for (int i = 0; i < context.Width; i++) { for (int j = 0; j < context.Height; j++) { var c = context.Pixels[j*context.Width + i]; byte a = (byte) (c >> 24); // Prevent division by zero int ai = a; if (ai == 0) { ai = 1; } ai = ((255 << 8)/ai); var color = Color.FromArgb( a, (byte) ((((c >> 16) & 0xFF)*ai) >> 8), (byte) ((((c >> 8) & 0xFF)*ai) >> 8), (byte) ((((c & 0xFF)*ai) >> 8))); if (colorsDictionary.ContainsKey(color)) { colorsDictionary[color]++; } else { colorsDictionary[color] = 1; } } } return colorsDictionary.OrderByDescending(b => b.Value).Select(b => b.Key).Take(k); } } catch (AccessViolationException) { MessageBox.Show("Tried to access protected memory. Try reloading picture."); } return null; }
private void DrawBodyPolygon(BitmapContext ctx, Body body) { var isStatic = body.IgnoresGravity; var pts = new int[body.Shape.Vertexes.Count() * 2 + 2]; var pos = body.State.Position; int i = 0; foreach (var v in body.Shape.Vertexes) { var vr = Vector2D.Rotate(pos.Angular, v); pts[i] = (int)(vr.X + pos.X); pts[i + 1] = (int)(vr.Y + pos.Y); i += 2; } pts[i] = pts[0]; pts[i + 1] = pts[1]; ctx.WriteableBitmap.FillPolygon(pts, isStatic ? _statBodyColor : _dynBodyColor); }
public BitmapRenderer(LWF lwf, BitmapContext context) : base(lwf) { m_context = context; m_matrix = new Matrix(0, 0, 0, 0, 0, 0); m_matrixForRender = new Matrix4x4(); m_colorMult = new UnityEngine.Color(); m_colorAdd = new UnityEngine.Color(); m_z = -1; m_updated = false; }
/// <summary> /// Draws an anti-aliased, alpha-blended, colored line by connecting two points using Wu's antialiasing algorithm /// Uses the pixels array and the width directly for best performance. /// </summary> /// <param name="context">An array containing the pixels as int RGBA value.</param> /// <param name="pixelWidth">The width of one scanline in the pixels array.</param> /// <param name="pixelHeight">The height of the bitmap.</param> /// <param name="x1">The x0.</param> /// <param name="y1">The y0.</param> /// <param name="x2">The x1.</param> /// <param name="y2">The y1.</param> /// <param name="sa">Alpha color component</param> /// <param name="sr">Premultiplied red color component</param> /// <param name="sg">Premultiplied green color component</param> /// <param name="sb">Premultiplied blue color component</param> public static void DrawLineWu(BitmapContext context, int pixelWidth, int pixelHeight, int x1, int y1, int x2, int y2, int sa, int sr, int sg, int sb) { // Perform cohen-sutherland clipping if either point is out of the viewport if (!CohenSutherlandLineClip(new Rect(0, 0, pixelWidth, pixelHeight), ref x1, ref y1, ref x2, ref y2)) return; var pixels = context.Pixels; const ushort INTENSITY_BITS = 8; const short NUM_LEVELS = 1 << INTENSITY_BITS; // 256 // mask used to compute 1-value by doing (value XOR mask) const ushort WEIGHT_COMPLEMENT_MASK = NUM_LEVELS - 1; // 255 // # of bits by which to shift ErrorAcc to get intensity level const ushort INTENSITY_SHIFT = (ushort)(16 - INTENSITY_BITS); // 8 ushort ErrorAdj, ErrorAcc; ushort ErrorAccTemp, Weighting; short DeltaX, DeltaY, XDir; int tmp; // ensure line runs from top to bottom if (y1 > y2) { tmp = y1; y1 = y2; y2 = tmp; tmp = x1; x1 = x2; x2 = tmp; } // draw initial pixel, which is always intersected by line to it's at 100% intensity pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, sr, sg, sb, pixels[y1 * pixelWidth + x1]); //bitmap.SetPixel(X0, Y0, BaseColor); DeltaX = (short)(x2 - x1); if (DeltaX >= 0) { XDir = 1; } else { XDir = -1; DeltaX = (short)-DeltaX; /* make DeltaX positive */ } // Special-case horizontal, vertical, and diagonal lines, which // require no weighting because they go right through the center of // every pixel; also avoids division by zero later DeltaY = (short)(y2 - y1); if (DeltaY == 0) // if horizontal line { while (DeltaX-- != 0) { x1 += XDir; pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, sr, sg, sb, pixels[y1 * pixelWidth + x1]); } return; } if (DeltaX == 0) // if vertical line { do { y1++; pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, sr, sg, sb, pixels[y1 * pixelWidth + x1]); } while (--DeltaY != 0); return; } if (DeltaX == DeltaY) // diagonal line { do { x1 += XDir; y1++; pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, sr, sg, sb, pixels[y1 * pixelWidth + x1]); } while (--DeltaY != 0); return; } // Line is not horizontal, diagonal, or vertical ErrorAcc = 0; // initialize the line error accumulator to 0 // Is this an X-major or Y-major line? if (DeltaY > DeltaX) { // Y-major line; calculate 16-bit fixed-point fractional part of a // pixel that X advances each time Y advances 1 pixel, truncating the // result so that we won't overrun the endpoint along the X axis ErrorAdj = (ushort)(((ulong)DeltaX << 16) / (ulong)DeltaY); // Draw all pixels other than the first and last while (--DeltaY != 0) { ErrorAccTemp = ErrorAcc; // remember current accumulated error ErrorAcc += ErrorAdj; // calculate error for next pixel if (ErrorAcc <= ErrorAccTemp) { // The error accumulator turned over, so advance the X coord */ x1 += XDir; } y1++; /* Y-major, so always advance Y */ // The IntensityBits most significant bits of ErrorAcc give us the // intensity weighting for this pixel, and the complement of the // weighting for the paired pixel Weighting = (ushort)(ErrorAcc >> INTENSITY_SHIFT); int weight = Weighting ^ WEIGHT_COMPLEMENT_MASK; pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, (sr * weight) >> 8, (sg * weight) >> 8, (sb * weight) >> 8, pixels[y1 * pixelWidth + x1]); weight = Weighting; pixels[y1 * pixelWidth + x1 + XDir] = AlphaBlend(sa, (sr * weight) >> 8, (sg * weight) >> 8, (sb * weight) >> 8, pixels[y1 * pixelWidth + x1 + XDir]); //bitmap.SetPixel(X0, Y0, 255 - (BaseColor + Weighting)); //bitmap.SetPixel(X0 + XDir, Y0, 255 - (BaseColor + (Weighting ^ WeightingComplementMask))); } // Draw the final pixel, which is always exactly intersected by the line and so needs no weighting pixels[y2 * pixelWidth + x2] = AlphaBlend(sa, sr, sg, sb, pixels[y2 * pixelWidth + x2]); //bitmap.SetPixel(X1, Y1, BaseColor); return; } // It's an X-major line; calculate 16-bit fixed-point fractional part of a // pixel that Y advances each time X advances 1 pixel, truncating the // result to avoid overrunning the endpoint along the X axis */ ErrorAdj = (ushort)(((ulong)DeltaY << 16) / (ulong)DeltaX); // Draw all pixels other than the first and last while (--DeltaX != 0) { ErrorAccTemp = ErrorAcc; // remember current accumulated error ErrorAcc += ErrorAdj; // calculate error for next pixel if (ErrorAcc <= ErrorAccTemp) // if error accumulator turned over { // advance the Y coord y1++; } x1 += XDir; // X-major, so always advance X // The IntensityBits most significant bits of ErrorAcc give us the // intensity weighting for this pixel, and the complement of the // weighting for the paired pixel Weighting = (ushort)(ErrorAcc >> INTENSITY_SHIFT); int weight = Weighting ^ WEIGHT_COMPLEMENT_MASK; pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, (sr * weight) >> 8, (sg * weight) >> 8, (sb * weight) >> 8, pixels[y1 * pixelWidth + x1]); weight = Weighting; pixels[(y1 + 1) * pixelWidth + x1] = AlphaBlend(sa, (sr * weight) >> 8, (sg * weight) >> 8, (sb * weight) >> 8, pixels[(y1 + 1) * pixelWidth + x1]); //bitmap.SetPixel(X0, Y0, 255 - (BaseColor + Weighting)); //bitmap.SetPixel(X0, Y0 + 1, // 255 - (BaseColor + (Weighting ^ WeightingComplementMask))); } // Draw the final pixel, which is always exactly intersected by the line and thus needs no weighting pixels[y2 * pixelWidth + x2] = AlphaBlend(sa, sr, sg, sb, pixels[y2 * pixelWidth + x2]); //bitmap.SetPixel(X1, Y1, BaseColor); }
/// <summary> /// Draws a colored line by connecting two points using an optimized DDA. /// Uses the pixels array and the width directly for best performance. /// </summary> /// <param name="context">The context containing the pixels as int RGBA value.</param> /// <param name="pixelWidth">The width of one scanline in the pixels array.</param> /// <param name="pixelHeight">The height of the bitmap.</param> /// <param name="x1">The x-coordinate of the start point.</param> /// <param name="y1">The y-coordinate of the start point.</param> /// <param name="x2">The x-coordinate of the end point.</param> /// <param name="y2">The y-coordinate of the end point.</param> /// <param name="color">The color for the line.</param> public static void DrawLine(BitmapContext context, int pixelWidth, int pixelHeight, int x1, int y1, int x2, int y2, int color) { // Perform cohen-sutherland clipping if either point is out of the viewport if (!CohenSutherlandLineClip(new Rect(0, 0, pixelWidth, pixelHeight), ref x1, ref y1, ref x2, ref y2)) return; var pixels = context.Pixels; // Distance start and end point int dx = x2 - x1; int dy = y2 - y1; const int PRECISION_SHIFT = 8; // Determine slope (absolute value) int lenX, lenY; if (dy >= 0) { lenY = dy; } else { lenY = -dy; } if (dx >= 0) { lenX = dx; } else { lenX = -dx; } if (lenX > lenY) { // x increases by +/- 1 if (dx < 0) { int t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; } // Init steps and start int incy = (dy << PRECISION_SHIFT) / dx; int y1s = y1 << PRECISION_SHIFT; int y2s = y2 << PRECISION_SHIFT; int hs = pixelHeight << PRECISION_SHIFT; if (y1 < y2) { if (y1 >= pixelHeight || y2 < 0) { return; } if (y1s < 0) { if (incy == 0) { return; } int oldy1s = y1s; // Find lowest y1s that is greater or equal than 0. y1s = incy - 1 + ((y1s + 1) % incy); x1 += (y1s - oldy1s) / incy; } if (y2s >= hs) { if (incy != 0) { // Find highest y2s that is less or equal than ws - 1. // y2s = y1s + n * incy. Find n. y2s = hs - 1 - (hs - 1 - y1s) % incy; x2 = x1 + (y2s - y1s) / incy; } } } else { if (y2 >= pixelHeight || y1 < 0) { return; } if (y1s >= hs) { if (incy == 0) { return; } int oldy1s = y1s; // Find highest y1s that is less or equal than ws - 1. // y1s = oldy1s + n * incy. Find n. y1s = hs - 1 + (incy - (hs - 1 - oldy1s) % incy); x1 += (y1s - oldy1s) / incy; } if (y2s < 0) { if (incy != 0) { // Find lowest y2s that is greater or equal than 0. // y2s = y1s + n * incy. Find n. y2s = y1s % incy; x2 = x1 + (y2s - y1s) / incy; } } } if (x1 < 0) { y1s -= incy * x1; x1 = 0; } if (x2 >= pixelWidth) { x2 = pixelWidth - 1; } int ys = y1s; // Walk the line! int y = ys >> PRECISION_SHIFT; int previousY = y; int index = x1 + y * pixelWidth; int k = incy < 0 ? 1 - pixelWidth : 1 + pixelWidth; for (int x = x1; x <= x2; ++x) { pixels[index] = color; ys += incy; y = ys >> PRECISION_SHIFT; if (y != previousY) { previousY = y; index += k; } else { ++index; } } } else { // Prevent division by zero if (lenY == 0) { return; } if (dy < 0) { int t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; } // Init steps and start int x1s = x1 << PRECISION_SHIFT; int x2s = x2 << PRECISION_SHIFT; int ws = pixelWidth << PRECISION_SHIFT; int incx = (dx << PRECISION_SHIFT) / dy; if (x1 < x2) { if (x1 >= pixelWidth || x2 < 0) { return; } if (x1s < 0) { if (incx == 0) { return; } int oldx1s = x1s; // Find lowest x1s that is greater or equal than 0. x1s = incx - 1 + ((x1s + 1) % incx); y1 += (x1s - oldx1s) / incx; } if (x2s >= ws) { if (incx != 0) { // Find highest x2s that is less or equal than ws - 1. // x2s = x1s + n * incx. Find n. x2s = ws - 1 - (ws - 1 - x1s) % incx; y2 = y1 + (x2s - x1s) / incx; } } } else { if (x2 >= pixelWidth || x1 < 0) { return; } if (x1s >= ws) { if (incx == 0) { return; } int oldx1s = x1s; // Find highest x1s that is less or equal than ws - 1. // x1s = oldx1s + n * incx. Find n. x1s = ws - 1 + (incx - (ws - 1 - oldx1s) % incx); y1 += (x1s - oldx1s) / incx; } if (x2s < 0) { if (incx != 0) { // Find lowest x2s that is greater or equal than 0. // x2s = x1s + n * incx. Find n. x2s = x1s % incx; y2 = y1 + (x2s - x1s) / incx; } } } if (y1 < 0) { x1s -= incx * y1; y1 = 0; } if (y2 >= pixelHeight) { y2 = pixelHeight - 1; } int index = x1s; int indexBaseValue = y1 * pixelWidth; // Walk the line! var inc = (pixelWidth << PRECISION_SHIFT) + incx; for (int y = y1; y <= y2; ++y) { pixels[indexBaseValue + (index >> PRECISION_SHIFT)] = color; index += inc; } } }
/// <summary> /// Draws an anti-aliased line, using an optimized version of Gupta-Sproull algorithm /// From http://nokola.com/blog/post/2010/10/14/Anti-aliased-Lines-And-Optimizing-Code-for-Windows-Phone-7e28093First-Look.aspx /// <param name="context">The context containing the pixels as int RGBA value.</param> /// <param name="pixelWidth">The width of one scanline in the pixels array.</param> /// <param name="pixelHeight">The height of the bitmap.</param> /// <param name="x1">The x-coordinate of the start point.</param> /// <param name="y1">The y-coordinate of the start point.</param> /// <param name="x2">The x-coordinate of the end point.</param> /// <param name="y2">The y-coordinate of the end point.</param> /// <param name="color">The color for the line.</param> /// </summary> public static void DrawLineAa(BitmapContext context, int pixelWidth, int pixelHeight, int x1, int y1, int x2, int y2, int color) { if ((x1 == x2) && (y1 == y2)) return; // edge case causing invDFloat to overflow, found by Shai Rubinshtein // Perform cohen-sutherland clipping if either point is out of the viewport if (!CohenSutherlandLineClip(new Rect(0, 0, pixelWidth, pixelHeight), ref x1, ref y1, ref x2, ref y2)) return; if (x1 < 1) x1 = 1; if (x1 > pixelWidth - 2) x1 = pixelWidth - 2; if (y1 < 1) y1 = 1; if (y1 > pixelHeight - 2) y1 = pixelHeight - 2; if (x2 < 1) x2 = 1; if (x2 > pixelWidth - 2) x2 = pixelWidth - 2; if (y2 < 1) y2 = 1; if (y2 > pixelHeight - 2) y2 = pixelHeight - 2; var addr = y1 * pixelWidth + x1; var dx = x2 - x1; var dy = y2 - y1; int du; int dv; int u; int v; int uincr; int vincr; // Extract color var a = (color >> 24) & 0xFF; var srb = (uint)(color & 0x00FF00FF); var sg = (uint)((color >> 8) & 0xFF); // By switching to (u,v), we combine all eight octants int adx = dx, ady = dy; if (dx < 0) adx = -dx; if (dy < 0) ady = -dy; if (adx > ady) { du = adx; dv = ady; u = x2; v = y2; uincr = 1; vincr = pixelWidth; if (dx < 0) uincr = -uincr; if (dy < 0) vincr = -vincr; } else { du = ady; dv = adx; u = y2; v = x2; uincr = pixelWidth; vincr = 1; if (dy < 0) uincr = -uincr; if (dx < 0) vincr = -vincr; } var uend = u + du; var d = (dv << 1) - du; // Initial value as in Bresenham's var incrS = dv << 1; // Δd for straight increments var incrD = (dv - du) << 1; // Δd for diagonal increments var invDFloat = 1.0 / (4.0 * Math.Sqrt(du * du + dv * dv)); // Precomputed inverse denominator var invD2DuFloat = 0.75 - 2.0 * (du * invDFloat); // Precomputed constant const int PRECISION_SHIFT = 10; // result distance should be from 0 to 1 << PRECISION_SHIFT, mapping to a range of 0..1 const int PRECISION_MULTIPLIER = 1 << PRECISION_SHIFT; var invD = (int)(invDFloat * PRECISION_MULTIPLIER); var invD2Du = (int)(invD2DuFloat * PRECISION_MULTIPLIER * a); var zeroDot75 = (int)(0.75 * PRECISION_MULTIPLIER * a); var invDMulAlpha = invD * a; var duMulInvD = du * invDMulAlpha; // used to help optimize twovdu * invD var dMulInvD = d * invDMulAlpha; // used to help optimize twovdu * invD //int twovdu = 0; // Numerator of distance; starts at 0 var twovduMulInvD = 0; // since twovdu == 0 var incrSMulInvD = incrS * invDMulAlpha; var incrDMulInvD = incrD * invDMulAlpha; do { AlphaBlendNormalOnPremultiplied(context, addr, (zeroDot75 - twovduMulInvD) >> PRECISION_SHIFT, srb, sg); AlphaBlendNormalOnPremultiplied(context, addr + vincr, (invD2Du + twovduMulInvD) >> PRECISION_SHIFT, srb, sg); AlphaBlendNormalOnPremultiplied(context, addr - vincr, (invD2Du - twovduMulInvD) >> PRECISION_SHIFT, srb, sg); if (d < 0) { // choose straight (u direction) twovduMulInvD = dMulInvD + duMulInvD; d += incrS; dMulInvD += incrSMulInvD; } else { // choose diagonal (u+v direction) twovduMulInvD = dMulInvD - duMulInvD; d += incrD; dMulInvD += incrDMulInvD; v++; addr += vincr; } u++; addr += uincr; } while (u < uend); }
/// <summary> /// Creates a new resized bitmap. /// </summary> /// <param name="srcContext">The source context.</param> /// <param name="widthSource">The width of the source pixels.</param> /// <param name="heightSource">The height of the source pixels.</param> /// <param name="width">The new desired width.</param> /// <param name="height">The new desired height.</param> /// <param name="interpolation">The interpolation method that should be used.</param> /// <returns>A new bitmap that is a resized version of the input.</returns> public static int[] Resize(BitmapContext srcContext, int widthSource, int heightSource, int width, int height, Interpolation interpolation) { var pixels = srcContext.Pixels; var pd = new int[width * height]; var xs = (float)widthSource / width; var ys = (float)heightSource / height; float fracx, fracy, ifracx, ifracy, sx, sy, l0, l1, rf, gf, bf; int c, x0, x1, y0, y1; byte c1a, c1r, c1g, c1b, c2a, c2r, c2g, c2b, c3a, c3r, c3g, c3b, c4a, c4r, c4g, c4b; byte a, r, g, b; // Nearest Neighbor if (interpolation == Interpolation.NearestNeighbor) { var srcIdx = 0; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { sx = x * xs; sy = y * ys; x0 = (int)sx; y0 = (int)sy; pd[srcIdx++] = pixels[y0 * widthSource + x0]; } } } // Bilinear else if (interpolation == Interpolation.Bilinear) { var srcIdx = 0; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { sx = x * xs; sy = y * ys; x0 = (int)sx; y0 = (int)sy; // Calculate coordinates of the 4 interpolation points fracx = sx - x0; fracy = sy - y0; ifracx = 1f - fracx; ifracy = 1f - fracy; x1 = x0 + 1; if (x1 >= widthSource) { x1 = x0; } y1 = y0 + 1; if (y1 >= heightSource) { y1 = y0; } // Read source color c = pixels[y0 * widthSource + x0]; c1a = (byte)(c >> 24); c1r = (byte)(c >> 16); c1g = (byte)(c >> 8); c1b = (byte)(c); c = pixels[y0 * widthSource + x1]; c2a = (byte)(c >> 24); c2r = (byte)(c >> 16); c2g = (byte)(c >> 8); c2b = (byte)(c); c = pixels[y1 * widthSource + x0]; c3a = (byte)(c >> 24); c3r = (byte)(c >> 16); c3g = (byte)(c >> 8); c3b = (byte)(c); c = pixels[y1 * widthSource + x1]; c4a = (byte)(c >> 24); c4r = (byte)(c >> 16); c4g = (byte)(c >> 8); c4b = (byte)(c); // Calculate colors // Alpha l0 = ifracx * c1a + fracx * c2a; l1 = ifracx * c3a + fracx * c4a; a = (byte)(ifracy * l0 + fracy * l1); // Red l0 = ifracx * c1r * c1a + fracx * c2r * c2a; l1 = ifracx * c3r * c3a + fracx * c4r * c4a; rf = ifracy * l0 + fracy * l1; // Green l0 = ifracx * c1g * c1a + fracx * c2g * c2a; l1 = ifracx * c3g * c3a + fracx * c4g * c4a; gf = ifracy * l0 + fracy * l1; // Blue l0 = ifracx * c1b * c1a + fracx * c2b * c2a; l1 = ifracx * c3b * c3a + fracx * c4b * c4a; bf = ifracy * l0 + fracy * l1; // Divide by alpha if (a > 0) { rf = rf / a; gf = gf / a; bf = bf / a; } // Cast to byte r = (byte)rf; g = (byte)gf; b = (byte)bf; // Write destination pd[srcIdx++] = (a << 24) | (r << 16) | (g << 8) | b; } } } return pd; }
private static void DrawHorizontally(BitmapContext context, int x1, int x2, int y, int dotSpace, int dotLength, int color) { int width = context.Width; int height = context.Height; var pixels = context.Pixels; bool on = true; int spaceCnt = 0; for (int i = x1; i <= x2; i++) { if (i < 1) { continue; } if (i >= width) { break; } if (y >= height) { break; } if (on) { //bmp.SetPixel(i, y, color); //var idx = GetIndex(i, y, width); var idx = (y - 1) * width + i - 1; pixels[idx] = color; on = i % dotLength != 0; spaceCnt = 0; } else { spaceCnt++; on = spaceCnt % dotSpace == 0; } //System.Diagnostics.Debug.WriteLine($"{i},{y}, on = {on}"); } }
private static void AddBodyToContext(IBody body, BitmapContext context, Color boneColor, Color jointColor) { DrawBonesAndJoints(body, context, boneColor, jointColor); RenderClippedEdges(body, context); }
public static unsafe void BlockCopy(BitmapContext src, int srcOffset, BitmapContext dest, int destOffset, int count) { NativeMethods.CopyUnmanagedMemory((byte *)src.Pixels, srcOffset, (byte *)dest.Pixels, destOffset, count); }
private static void AALineQ1(int width, int height, BitmapContext context, int x1, int y1, int x2, int y2, Int32 color, bool minEdge, bool leftEdge) { Byte off = 0; if (minEdge) { off = 0xff; } if (x1 == x2) { return; } if (y1 == y2) { return; } var buffer = context.Pixels; if (y1 > y2) { Swap(ref x1, ref x2); Swap(ref y1, ref y2); } var deltax = (x2 - x1); var deltay = (y2 - y1); if (x1 > x2) { deltax = (x1 - x2); } var x = x1; var y = y1; UInt16 m = 0; if (deltax > deltay) { m = (ushort)(((deltay << 16) / deltax)); } else { m = (ushort)(((deltax << 16) / deltay)); } UInt16 e = 0; var a = (byte)((color & 0xff000000) >> 24); var r = (byte)((color & 0x00ff0000) >> 16); var g = (byte)((color & 0x0000ff00) >> 8); var b = (byte)((color & 0x000000ff) >> 0); Byte rs, gs, bs; Byte rd, gd, bd; Int32 d; var ta = a; e = 0; if (deltax >= deltay) { while (deltax-- != 0) { if ((UInt16)(e + m) <= e) // Roll { y++; } e += m; if (x1 < x2) { x++; } else { x--; } if (y < 0 || y >= height) { continue; } if (leftEdge) { leftEdgeX[y] = Math.Max(x + 1, leftEdgeX[y]); } else { rightEdgeX[y] = Math.Min(x - 1, rightEdgeX[y]); } if (x < 0 || x >= width) { continue; } // ta = (byte)((a * (UInt16)(((((UInt16)(e >> 8))) ^ off))) >> 8); rs = r; gs = g; bs = b; d = buffer[y * width + x]; rd = (byte)((d & 0x00ff0000) >> 16); gd = (byte)((d & 0x0000ff00) >> 8); bd = (byte)((d & 0x000000ff) >> 0); rd = (byte)((rs * ta + rd * (0xff - ta)) >> 8); gd = (byte)((gs * ta + gd * (0xff - ta)) >> 8); bd = (byte)((bs * ta + bd * (0xff - ta)) >> 8); buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0); // } } else { off ^= 0xff; while (--deltay != 0) { if ((UInt16)(e + m) <= e) // Roll { if (x1 < x2) { x++; } else { x--; } } e += m; y++; if (x < 0 || x >= width) { continue; } if (y < 0 || y >= height) { continue; } // ta = (byte)((a * (UInt16)(((((UInt16)(e >> 8))) ^ off))) >> 8); rs = r; gs = g; bs = b; d = buffer[y * width + x]; rd = (byte)((d & 0x00ff0000) >> 16); gd = (byte)((d & 0x0000ff00) >> 8); bd = (byte)((d & 0x000000ff) >> 0); rd = (byte)((rs * ta + rd * (0xff - ta)) >> 8); gd = (byte)((gs * ta + gd * (0xff - ta)) >> 8); bd = (byte)((bs * ta + bd * (0xff - ta)) >> 8); buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0); if (leftEdge) { leftEdgeX[y] = x + 1; } else { rightEdgeX[y] = x - 1; } } } }
/// <summary> /// Renders a bitmap using any affine transformation and transparency into this bitmap /// Unlike Silverlight's Render() method, this one uses 2-3 times less memory, and is the same or better quality /// The algorithm is simple dx/dy (bresenham-like) step by step painting, optimized with fixed point and fast bilinear filtering /// It's used in Fantasia Painter for drawing stickers and 3D objects on screen /// </summary> /// <param name="bmp">Destination bitmap.</param> /// <param name="source">The source WriteableBitmap.</param> /// <param name="shouldClear">If true, the the destination bitmap will be set to all clear (0) before rendering.</param> /// <param name="opacity">opacity of the source bitmap to render, between 0 and 1 inclusive</param> /// <param name="transform">Transformation to apply</param> public static void BlitRender(this WriteableBitmap bmp, WriteableBitmap source, bool shouldClear = true, float opacity = 1f, GeneralTransform transform = null) { const int PRECISION_SHIFT = 10; const int PRECISION_VALUE = (1 << PRECISION_SHIFT); const int PRECISION_MASK = PRECISION_VALUE - 1; using (BitmapContext destContext = bmp.GetBitmapContext()) { if (transform == null) { transform = new MatrixTransform(); } var destPixels = destContext.Pixels; int destWidth = destContext.Width; int destHeight = destContext.Height; var inverse = transform.Inverse; if (shouldClear) { destContext.Clear(); } using (BitmapContext sourceContext = source.GetBitmapContext(ReadWriteMode.ReadOnly)) { var sourcePixels = sourceContext.Pixels; int sourceWidth = sourceContext.Width; int sourceHeight = sourceContext.Height; Rect sourceRect = new Rect(0, 0, sourceWidth, sourceHeight); Rect destRect = new Rect(0, 0, destWidth, destHeight); Rect bounds = transform.TransformBounds(sourceRect); bounds.Intersect(destRect); int startX = (int)bounds.Left; int startY = (int)bounds.Top; int endX = (int)bounds.Right; int endY = (int)bounds.Bottom; #if NETFX_CORE Point zeroZero = inverse.TransformPoint(new Point(startX, startY)); Point oneZero = inverse.TransformPoint(new Point(startX + 1, startY)); Point zeroOne = inverse.TransformPoint(new Point(startX, startY + 1)); #else Point zeroZero = inverse.Transform(new Point(startX, startY)); Point oneZero = inverse.Transform(new Point(startX + 1, startY)); Point zeroOne = inverse.Transform(new Point(startX, startY + 1)); #endif float sourceXf = ((float)zeroZero.X); float sourceYf = ((float)zeroZero.Y); int dxDx = (int)((((float)oneZero.X) - sourceXf) * PRECISION_VALUE); // for 1 unit in X coord, how much does X change in source texture? int dxDy = (int)((((float)oneZero.Y) - sourceYf) * PRECISION_VALUE); // for 1 unit in X coord, how much does Y change in source texture? int dyDx = (int)((((float)zeroOne.X) - sourceXf) * PRECISION_VALUE); // for 1 unit in Y coord, how much does X change in source texture? int dyDy = (int)((((float)zeroOne.Y) - sourceYf) * PRECISION_VALUE); // for 1 unit in Y coord, how much does Y change in source texture? int sourceX = (int)(((float)zeroZero.X) * PRECISION_VALUE); int sourceY = (int)(((float)zeroZero.Y) * PRECISION_VALUE); int sourceWidthFixed = sourceWidth << PRECISION_SHIFT; int sourceHeightFixed = sourceHeight << PRECISION_SHIFT; int opacityInt = (int)(opacity * 255); int index = 0; for (int destY = startY; destY < endY; destY++) { index = destY * destWidth + startX; int savedSourceX = sourceX; int savedSourceY = sourceY; for (int destX = startX; destX < endX; destX++) { if ((sourceX >= 0) && (sourceX < sourceWidthFixed) && (sourceY >= 0) && (sourceY < sourceHeightFixed)) { // bilinear filtering int xFloor = sourceX >> PRECISION_SHIFT; int yFloor = sourceY >> PRECISION_SHIFT; if (xFloor < 0) { xFloor = 0; } if (yFloor < 0) { yFloor = 0; } int xCeil = xFloor + 1; int yCeil = yFloor + 1; if (xCeil >= sourceWidth) { xFloor = sourceWidth - 1; xCeil = 0; } else { xCeil = 1; } if (yCeil >= sourceHeight) { yFloor = sourceHeight - 1; yCeil = 0; } else { yCeil = sourceWidth; } int i1 = yFloor * sourceWidth + xFloor; int p1 = sourcePixels[i1]; int p2 = sourcePixels[i1 + xCeil]; int p3 = sourcePixels[i1 + yCeil]; int p4 = sourcePixels[i1 + yCeil + xCeil]; int xFrac = sourceX & PRECISION_MASK; int yFrac = sourceY & PRECISION_MASK; // alpha byte a1 = (byte)(p1 >> 24); byte a2 = (byte)(p2 >> 24); byte a3 = (byte)(p3 >> 24); byte a4 = (byte)(p4 >> 24); int comp1, comp2; byte a; if ((a1 == a2) && (a1 == a3) && (a1 == a4)) { if (a1 == 0) { destPixels[index] = 0; sourceX += dxDx; sourceY += dxDy; index++; continue; } a = a1; } else { comp1 = a1 + ((xFrac * (a2 - a1)) >> PRECISION_SHIFT); comp2 = a3 + ((xFrac * (a4 - a3)) >> PRECISION_SHIFT); a = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT)); } // red comp1 = ((byte)(p1 >> 16)) + ((xFrac * (((byte)(p2 >> 16)) - ((byte)(p1 >> 16)))) >> PRECISION_SHIFT); comp2 = ((byte)(p3 >> 16)) + ((xFrac * (((byte)(p4 >> 16)) - ((byte)(p3 >> 16)))) >> PRECISION_SHIFT); byte r = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT)); // green comp1 = ((byte)(p1 >> 8)) + ((xFrac * (((byte)(p2 >> 8)) - ((byte)(p1 >> 8)))) >> PRECISION_SHIFT); comp2 = ((byte)(p3 >> 8)) + ((xFrac * (((byte)(p4 >> 8)) - ((byte)(p3 >> 8)))) >> PRECISION_SHIFT); byte g = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT)); // blue comp1 = ((byte)p1) + ((xFrac * (((byte)p2) - ((byte)p1))) >> PRECISION_SHIFT); comp2 = ((byte)p3) + ((xFrac * (((byte)p4) - ((byte)p3))) >> PRECISION_SHIFT); byte b = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT)); // save updated pixel if (opacityInt != 255) { a = (byte)((a * opacityInt) >> 8); r = (byte)((r * opacityInt) >> 8); g = (byte)((g * opacityInt) >> 8); b = (byte)((b * opacityInt) >> 8); } destPixels[index] = (a << 24) | (r << 16) | (g << 8) | b; } sourceX += dxDx; sourceY += dxDy; index++; } sourceX = savedSourceX + dyDx; sourceY = savedSourceY + dyDy; } } } }
private static void RenderClippedEdges(IBody body, BitmapContext context) { try { if (body.ClippedEdges.HasFlag(FrameEdges.Bottom)) { context.WriteableBitmap.FillRectangle( 0, (int)_height - (int)_clipBoundsThickness, (int)_width, (int)_height, Colors.Red); } if (body.ClippedEdges.HasFlag(FrameEdges.Top)) { context.WriteableBitmap.FillRectangle( 0, 0, (int)_width, (int)_clipBoundsThickness, Colors.Red); } if (body.ClippedEdges.HasFlag(FrameEdges.Left)) { context.WriteableBitmap.FillRectangle( 0, 0, (int)_clipBoundsThickness, (int)_height, Colors.Red); } if (body.ClippedEdges.HasFlag(FrameEdges.Right)) { context.WriteableBitmap.FillRectangle( (int)_width - (int)_clipBoundsThickness, 0, (int)_width, (int)_height, Colors.Red); } } catch { } }
private static void DrawBonesAndJoints(IBody body, BitmapContext context, Color boneColor, Color jointColor) { foreach (var bone in CustomBoneType.DrawnBones) { DrawBone(body, context, bone, boneColor); } Color inferredJointColor = jointColor; inferredJointColor.A = 128; // Render Joints foreach (var joint in body.Joints.Values) { if (joint.TrackingState == TrackingState.NotTracked) { continue; } var point = GetDepthSpacePoint(joint, body.HasMappedDepthPositions); context.WriteableBitmap.FillEllipseCentered( (int)point.X, (int)point.Y, (int)_jointThickness, (int)_jointThickness, joint.TrackingState == TrackingState.Inferred ? inferredJointColor : jointColor); } }
private static void DrawBone(IBody body, BitmapContext context, CustomBoneType bone, Color color) { var startJoint = body.Joints[bone.StartJoint]; var endJoint = body.Joints[bone.EndJoint]; // If we can't find either of these joints, exit if (startJoint.TrackingState == TrackingState.NotTracked || endJoint.TrackingState == TrackingState.NotTracked) { return; } // Don't draw if both points are inferred if (startJoint.TrackingState == TrackingState.Inferred && endJoint.TrackingState == TrackingState.Inferred) { return; } // If either isn't tracked, it is "inferred" if (startJoint.TrackingState != TrackingState.Tracked || endJoint.TrackingState != TrackingState.Tracked) { color.A = 192; } var startPoint = GetDepthSpacePoint(startJoint, body.HasMappedDepthPositions); var endPoint = GetDepthSpacePoint(endJoint, body.HasMappedDepthPositions); context.WriteableBitmap.DrawLineAa( (int)startPoint.X, (int)startPoint.Y, (int)endPoint.X, (int)endPoint.Y, color); }
public BitmapRenderer(LWF lwf, BitmapContext context) : base(lwf) { m_context = context; m_matrix = new Matrix4x4(); m_colorMult = new UnityEngine.Color(); m_colorAdd = new UnityEngine.Color(); m_available = false; if (m_context != null) m_context.factory.AddBitmap(); }
private static void AAWidthLine(int width, int height, BitmapContext context, float x1, float y1, float x2, float y2, float lineWidth, Int32 color) { // Perform cohen-sutherland clipping if either point is out of the viewport if (!CohenSutherlandLineClip(new Rect(0, 0, width, height), ref x1, ref y1, ref x2, ref y2)) { return; } if (lineWidth <= 0) { return; } var buffer = context.Pixels; if (y1 > y2) { Swap(ref x1, ref x2); Swap(ref y1, ref y2); } if (x1 == x2) { x1 -= (int)lineWidth / 2; x2 += (int)lineWidth / 2; if (x1 < 0) { x1 = 0; } if (x2 < 0) { return; } if (x1 >= width) { return; } if (x2 >= width) { x2 = width - 1; } if (y1 >= height || y2 < 0) { return; } if (y1 < 0) { y1 = 0; } if (y2 >= height) { y2 = height - 1; } for (var x = (int)x1; x <= x2; x++) { for (var y = (int)y1; y <= y2; y++) { var a = (byte)((color & 0xff000000) >> 24); var r = (byte)((color & 0x00ff0000) >> 16); var g = (byte)((color & 0x0000ff00) >> 8); var b = (byte)((color & 0x000000ff) >> 0); byte rs, gs, bs; byte rd, gd, bd; int d; rs = r; gs = g; bs = b; d = buffer[y * width + x]; rd = (byte)((d & 0x00ff0000) >> 16); gd = (byte)((d & 0x0000ff00) >> 8); bd = (byte)((d & 0x000000ff) >> 0); rd = (byte)((rs * a + rd * (0xff - a)) >> 8); gd = (byte)((gs * a + gd * (0xff - a)) >> 8); bd = (byte)((bs * a + bd * (0xff - a)) >> 8); buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0); } } return; } if (y1 == y2) { if (x1 > x2) { Swap(ref x1, ref x2); } y1 -= (int)lineWidth / 2; y2 += (int)lineWidth / 2; if (y1 < 0) { y1 = 0; } if (y2 < 0) { return; } if (y1 >= height) { return; } if (y2 >= height) { x2 = height - 1; } if (x1 >= width || y2 < 0) { return; } if (x1 < 0) { x1 = 0; } if (x2 >= width) { x2 = width - 1; } for (var x = (int)x1; x <= x2; x++) { for (var y = (int)y1; y <= y2; y++) { var a = (byte)((color & 0xff000000) >> 24); var r = (byte)((color & 0x00ff0000) >> 16); var g = (byte)((color & 0x0000ff00) >> 8); var b = (byte)((color & 0x000000ff) >> 0); Byte rs, gs, bs; Byte rd, gd, bd; Int32 d; rs = r; gs = g; bs = b; d = buffer[y * width + x]; rd = (byte)((d & 0x00ff0000) >> 16); gd = (byte)((d & 0x0000ff00) >> 8); bd = (byte)((d & 0x000000ff) >> 0); rd = (byte)((rs * a + rd * (0xff - a)) >> 8); gd = (byte)((gs * a + gd * (0xff - a)) >> 8); bd = (byte)((bs * a + bd * (0xff - a)) >> 8); buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0); } } return; } y1 += 1; y2 += 1; var slope = (y2 - y1) / (x2 - x1); var islope = (x2 - x1) / (y2 - y1); var m = slope; var w = lineWidth; var dx = x2 - x1; var dy = y2 - y1; var xtot = (float)(w * dy / Math.Sqrt(dx * dx + dy * dy)); var ytot = (float)(w * dx / Math.Sqrt(dx * dx + dy * dy)); var sm = dx * dy / (dx * dx + dy * dy); // Center it. x1 += xtot / 2; y1 -= ytot / 2; x2 += xtot / 2; y2 -= ytot / 2; // // var sx = -xtot; var sy = +ytot; var ix1 = (int)x1; var iy1 = (int)y1; var ix2 = (int)x2; var iy2 = (int)y2; var ix3 = (int)(x1 + sx); var iy3 = (int)(y1 + sy); var ix4 = (int)(x2 + sx); var iy4 = (int)(y2 + sy); if (lineWidth == 2) { if (Math.Abs(dy) < Math.Abs(dx)) { if (x1 < x2) { iy3 = iy1 + 2; iy4 = iy2 + 2; } else { iy1 = iy3 + 2; iy2 = iy4 + 2; } } else { ix1 = ix3 + 2; ix2 = ix4 + 2; } } var starty = Math.Min(Math.Min(iy1, iy2), Math.Min(iy3, iy4)); var endy = Math.Max(Math.Max(iy1, iy2), Math.Max(iy3, iy4)); if (starty < 0) { starty = -1; } if (endy >= height) { endy = height + 1; } for (var y = starty + 1; y < endy - 1; y++) { leftEdgeX[y] = -1 << 16; rightEdgeX[y] = 1 << 16 - 1; } AALineQ1(width, height, context, ix1, iy1, ix2, iy2, color, sy > 0, false); AALineQ1(width, height, context, ix3, iy3, ix4, iy4, color, sy < 0, true); if (lineWidth > 1) { AALineQ1(width, height, context, ix1, iy1, ix3, iy3, color, true, sy > 0); AALineQ1(width, height, context, ix2, iy2, ix4, iy4, color, false, sy < 0); } if (x1 < x2) { if (iy2 >= 0 && iy2 < height) { rightEdgeX[iy2] = Math.Min(ix2, rightEdgeX[iy2]); } if (iy3 >= 0 && iy3 < height) { leftEdgeX[iy3] = Math.Max(ix3, leftEdgeX[iy3]); } } else { if (iy1 >= 0 && iy1 < height) { rightEdgeX[iy1] = Math.Min(ix1, rightEdgeX[iy1]); } if (iy4 >= 0 && iy4 < height) { leftEdgeX[iy4] = Math.Max(ix4, leftEdgeX[iy4]); } } //return; for (var y = starty + 1; y < endy - 1; y++) { leftEdgeX[y] = Math.Max(leftEdgeX[y], 0); rightEdgeX[y] = Math.Min(rightEdgeX[y], width - 1); for (var x = leftEdgeX[y]; x <= rightEdgeX[y]; x++) { var a = (byte)((color & 0xff000000) >> 24); var r = (byte)((color & 0x00ff0000) >> 16); var g = (byte)((color & 0x0000ff00) >> 8); var b = (byte)((color & 0x000000ff) >> 0); Byte rs, gs, bs; Byte rd, gd, bd; Int32 d; rs = r; gs = g; bs = b; d = buffer[y * width + x]; rd = (byte)((d & 0x00ff0000) >> 16); gd = (byte)((d & 0x0000ff00) >> 8); bd = (byte)((d & 0x000000ff) >> 0); rd = (byte)((rs * a + rd * (0xff - a)) >> 8); gd = (byte)((gs * a + gd * (0xff - a)) >> 8); bd = (byte)((bs * a + bd * (0xff - a)) >> 8); buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0); } } }
public static unsafe void Blit(this WriteableBitmap bmp, Rect destRect, WriteableBitmap source, Rect sourceRect, Color color, WriteableBitmapExtensions.BlendMode blendMode) { if ((int)color.A == 0) { return; } bool flag1 = source.Format == PixelFormats.Pbgra32 || source.Format == PixelFormats.Prgba64 || source.Format == PixelFormats.Prgba128Float; int num1 = (int)destRect.Width; int num2 = (int)destRect.Height; using (BitmapContext bitmapContext1 = WriteableBitmapContextExtensions.GetBitmapContext(source, ReadWriteMode.ReadOnly)) { using (BitmapContext bitmapContext2 = WriteableBitmapContextExtensions.GetBitmapContext(bmp)) { int width1 = bitmapContext1.Width; int width2 = bitmapContext2.Width; int height = bitmapContext2.Height; Rect rect = new Rect(0.0, 0.0, (double)width2, (double)height); rect.Intersect(destRect); if (rect.IsEmpty) { return; } int * pixels1 = bitmapContext1.Pixels; int * pixels2 = bitmapContext2.Pixels; int length = bitmapContext1.Length; int num3 = (int)destRect.X; int num4 = (int)destRect.Y; int num5 = 0; int num6 = 0; int num7 = 0; int num8 = 0; int num9 = (int)color.A; int num10 = (int)color.R; int num11 = (int)color.G; int num12 = (int)color.B; bool flag2 = color != Colors.White; int num13 = (int)sourceRect.Width; double num14 = sourceRect.Width / destRect.Width; double num15 = sourceRect.Height / destRect.Height; int num16 = (int)sourceRect.X; int num17 = (int)sourceRect.Y; int num18 = -1; int num19 = -1; double num20 = (double)num17; int num21 = num4; for (int index1 = 0; index1 < num2; ++index1) { if (num21 >= 0 && num21 < height) { double num22 = (double)num16; int index2 = num3 + num21 * width2; int num23 = num3; int num24 = *pixels1; if (blendMode == WriteableBitmapExtensions.BlendMode.None && !flag2) { int num25 = (int)num22 + (int)num20 * width1; int num26 = num23 < 0 ? -num23 : 0; int num27 = num23 + num26; int num28 = width1 - num26; int num29 = num27 + num28 < width2 ? num28 : width2 - num27; if (num29 > num13) { num29 = num13; } if (num29 > num1) { num29 = num1; } BitmapContext.BlockCopy(bitmapContext1, (num25 + num26) * 4, bitmapContext2, (index2 + num26) * 4, num29 * 4); } else { for (int index3 = 0; index3 < num1; ++index3) { if (num23 >= 0 && num23 < width2) { if ((int)num22 != num18 || (int)num20 != num19) { int index4 = (int)num22 + (int)num20 * width1; if (index4 >= 0 && index4 < length) { num24 = pixels1[index4]; num8 = num24 >> 24 & (int)Byte.MaxValue; num5 = num24 >> 16 & (int)Byte.MaxValue; num6 = num24 >> 8 & (int)Byte.MaxValue; num7 = num24 & (int)Byte.MaxValue; if (flag2 && num8 != 0) { num8 = num8 * num9 * 32897 >> 23; num5 = (num5 * num10 * 32897 >> 23) * num9 * 32897 >> 23; num6 = (num6 * num11 * 32897 >> 23) * num9 * 32897 >> 23; num7 = (num7 * num12 * 32897 >> 23) * num9 * 32897 >> 23; num24 = num8 << 24 | num5 << 16 | num6 << 8 | num7; } } else { num8 = 0; } } if (blendMode == WriteableBitmapExtensions.BlendMode.None) { pixels2[index2] = num24; } else if (blendMode == WriteableBitmapExtensions.BlendMode.ColorKeying) { num5 = num24 >> 16 & (int)Byte.MaxValue; num6 = num24 >> 8 & (int)Byte.MaxValue; num7 = num24 & (int)Byte.MaxValue; if (num5 != (int)color.R || num6 != (int)color.G || num7 != (int)color.B) { pixels2[index2] = num24; } } else if (blendMode == WriteableBitmapExtensions.BlendMode.Mask) { int num25 = pixels2[index2]; int num26 = num25 >> 24 & (int)Byte.MaxValue; int num27 = num25 >> 16 & (int)Byte.MaxValue; int num28 = num25 >> 8 & (int)Byte.MaxValue; int num29 = num25 & (int)Byte.MaxValue; int num30 = num26 * num8 * 32897 >> 23 << 24 | num27 * num8 * 32897 >> 23 << 16 | num28 * num8 * 32897 >> 23 << 8 | num29 * num8 * 32897 >> 23; pixels2[index2] = num30; } else if (num8 > 0) { int num25 = pixels2[index2]; int num26 = num25 >> 24 & (int)Byte.MaxValue; if ((num8 == (int)Byte.MaxValue || num26 == 0) && (blendMode != WriteableBitmapExtensions.BlendMode.Additive && blendMode != WriteableBitmapExtensions.BlendMode.Subtractive) && blendMode != WriteableBitmapExtensions.BlendMode.Multiply) { pixels2[index2] = num24; } else { int num27 = num25 >> 16 & (int)Byte.MaxValue; int num28 = num25 >> 8 & (int)Byte.MaxValue; int num29 = num25 & (int)Byte.MaxValue; if (blendMode == WriteableBitmapExtensions.BlendMode.Alpha) { int num30 = (int)Byte.MaxValue - num8; num25 = !flag1 ? (num26 & (int)Byte.MaxValue) << 24 | (num5 * num8 + num30 * num27 >> 8 & (int)Byte.MaxValue) << 16 | (num6 * num8 + num30 * num28 >> 8 & (int)Byte.MaxValue) << 8 | num7 * num8 + num30 * num29 >> 8 & (int)Byte.MaxValue : (num26 & (int)Byte.MaxValue) << 24 | ((num5 << 8) + num30 * num27 >> 8 & (int)Byte.MaxValue) << 16 | ((num6 << 8) + num30 * num28 >> 8 & (int)Byte.MaxValue) << 8 | (num7 << 8) + num30 * num29 >> 8 & (int)Byte.MaxValue; } else if (blendMode == WriteableBitmapExtensions.BlendMode.Additive) { int num30 = (int)Byte.MaxValue <= num8 + num26 ? (int)Byte.MaxValue : num8 + num26; num25 = num30 << 24 | (num30 <= num5 + num27 ? num30 : num5 + num27) << 16 | (num30 <= num6 + num28 ? num30 : num6 + num28) << 8 | (num30 <= num7 + num29 ? num30 : num7 + num29); } else if (blendMode == WriteableBitmapExtensions.BlendMode.Subtractive) { num25 = num26 << 24 | (num5 >= num27 ? 0 : num5 - num27) << 16 | (num6 >= num28 ? 0 : num6 - num28) << 8 | (num7 >= num29 ? 0 : num7 - num29); } else if (blendMode == WriteableBitmapExtensions.BlendMode.Multiply) { int num30 = num8 * num26 + 128; int num31 = num5 * num27 + 128; int num32 = num6 * num28 + 128; int num33 = num7 * num29 + 128; int num34 = (num30 >> 8) + num30 >> 8; int num35 = (num31 >> 8) + num31 >> 8; int num36 = (num32 >> 8) + num32 >> 8; int num37 = (num33 >> 8) + num33 >> 8; num25 = num34 << 24 | (num34 <= num35 ? num34 : num35) << 16 | (num34 <= num36 ? num34 : num36) << 8 | (num34 <= num37 ? num34 : num37); } pixels2[index2] = num25; } } } ++num23; ++index2; num22 += num14; } } } num20 += num15; ++num21; } } } }
/// <summary> /// Draws a segment of a Cardinal spline (cubic) defined by four control points. /// </summary> /// <param name="x1">The x-coordinate of the 1st control point.</param> /// <param name="y1">The y-coordinate of the 1st control point.</param> /// <param name="x2">The x-coordinate of the 2nd control point.</param> /// <param name="y2">The y-coordinate of the 2nd control point.</param> /// <param name="x3">The x-coordinate of the 3rd control point.</param> /// <param name="y3">The y-coordinate of the 3rd control point.</param> /// <param name="x4">The x-coordinate of the 4th control point.</param> /// <param name="y4">The y-coordinate of the 4th control point.</param> /// <param name="tension">The tension of the curve defines the shape. Usually between 0 and 1. 0 would be a straight line.</param> /// <param name="color">The color.</param> /// <param name="context">The pixel context.</param> /// <param name="w">The width of the bitmap.</param> /// <param name="h">The height of the bitmap.</param> private static void DrawCurveSegment(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, float tension, int color, BitmapContext context, int w, int h) { // Determine distances between controls points (bounding rect) to find the optimal stepsize var minX = Math.Min(x1, Math.Min(x2, Math.Min(x3, x4))); var minY = Math.Min(y1, Math.Min(y2, Math.Min(y3, y4))); var maxX = Math.Max(x1, Math.Max(x2, Math.Max(x3, x4))); var maxY = Math.Max(y1, Math.Max(y2, Math.Max(y3, y4))); // Get slope var lenx = maxX - minX; var len = maxY - minY; if (lenx > len) { len = lenx; } // Prevent division by zero if (len != 0) { // Init vars var step = StepFactor / len; int tx1 = x2; int ty1 = y2; int tx2, ty2; // Calculate factors var sx1 = tension * (x3 - x1); var sy1 = tension * (y3 - y1); var sx2 = tension * (x4 - x2); var sy2 = tension * (y4 - y2); var ax = sx1 + sx2 + 2 * x2 - 2 * x3; var ay = sy1 + sy2 + 2 * y2 - 2 * y3; var bx = -2 * sx1 - sx2 - 3 * x2 + 3 * x3; var by = -2 * sy1 - sy2 - 3 * y2 + 3 * y3; // Interpolate for (var t = step; t <= 1; t += step) { var tSq = t * t; tx2 = (int)(ax * tSq * t + bx * tSq + sx1 * t + x2); ty2 = (int)(ay * tSq * t + by * tSq + sy1 * t + y2); // Draw line DrawLine(context, w, h, tx1, ty1, tx2, ty2, color); tx1 = tx2; ty1 = ty2; } // Prevent rounding gap DrawLine(context, w, h, tx1, ty1, x3, y3, color); } }
/// <summary> /// Draws a filled, cubic Beziér spline defined by start, end and two control points. /// </summary> /// <param name="x1">The x-coordinate of the start point.</param> /// <param name="y1">The y-coordinate of the start point.</param> /// <param name="cx1">The x-coordinate of the 1st control point.</param> /// <param name="cy1">The y-coordinate of the 1st control point.</param> /// <param name="cx2">The x-coordinate of the 2nd control point.</param> /// <param name="cy2">The y-coordinate of the 2nd control point.</param> /// <param name="x2">The x-coordinate of the end point.</param> /// <param name="y2">The y-coordinate of the end point.</param> /// <param name="color">The color.</param> /// <param name="context">The context with the pixels.</param> /// <param name="w">The width of the bitmap.</param> /// <param name="h">The height of the bitmap.</param> private static List<int> ComputeBezierPoints(int x1, int y1, int cx1, int cy1, int cx2, int cy2, int x2, int y2, int color, BitmapContext context, int w, int h) { var pixels = context.Pixels; // Determine distances between controls points (bounding rect) to find the optimal stepsize var minX = Math.Min(x1, Math.Min(cx1, Math.Min(cx2, x2))); var minY = Math.Min(y1, Math.Min(cy1, Math.Min(cy2, y2))); var maxX = Math.Max(x1, Math.Max(cx1, Math.Max(cx2, x2))); var maxY = Math.Max(y1, Math.Max(cy1, Math.Max(cy2, y2))); // Get slope var lenx = maxX - minX; var len = maxY - minY; if (lenx > len) { len = lenx; } // Prevent divison by zero var list = new List<int>(); if (len != 0) { // Init vars var step = StepFactor / len; int tx = x1; int ty = y1; // Interpolate for (var t = 0f; t <= 1; t += step) { var tSq = t * t; var t1 = 1 - t; var t1Sq = t1 * t1; tx = (int)(t1 * t1Sq * x1 + 3 * t * t1Sq * cx1 + 3 * t1 * tSq * cx2 + t * tSq * x2); ty = (int)(t1 * t1Sq * y1 + 3 * t * t1Sq * cy1 + 3 * t1 * tSq * cy2 + t * tSq * y2); list.Add(tx); list.Add(ty); } // Prevent rounding gap list.Add(x2); list.Add(y2); } return list; }
private static void DrawVertically(BitmapContext context, int x, int y1, int y2, int dotSpace, int dotLength, int color) { int width = context.Width; int height = context.Height; if (x < 0 || x > width) { return; } var pixels = context.Pixels; bool on = true; int spaceCnt = 0; for (int i = y1; i <= y2; i++) { if (i < 1) { continue; } if (i >= height) { break; } if (on) { //bmp.SetPixel(x, i, color); //var idx = GetIndex(x, i, width); var idx = (i - 1) * width + x - 1; pixels[idx] = color; on = i % dotLength != 0; spaceCnt = 0; } else { spaceCnt++; on = spaceCnt % dotSpace == 0; } //System.Diagnostics.Debug.WriteLine($"{x},{i}, on = {on}"); } }
/// <summary> /// Computes the discrete segment points of a Cardinal spline (cubic) defined by four control points. /// </summary> /// <param name="x1">The x-coordinate of the 1st control point.</param> /// <param name="y1">The y-coordinate of the 1st control point.</param> /// <param name="x2">The x-coordinate of the 2nd control point.</param> /// <param name="y2">The y-coordinate of the 2nd control point.</param> /// <param name="x3">The x-coordinate of the 3rd control point.</param> /// <param name="y3">The y-coordinate of the 3rd control point.</param> /// <param name="x4">The x-coordinate of the 4th control point.</param> /// <param name="y4">The y-coordinate of the 4th control point.</param> /// <param name="tension">The tension of the curve defines the shape. Usually between 0 and 1. 0 would be a straight line.</param> /// <param name="color">The color.</param> /// <param name="context">The context with the pixels.</param> /// <param name="w">The width of the bitmap.</param> /// <param name="h">The height of the bitmap.</param> private static List<int> ComputeSegmentPoints(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, float tension, int color, BitmapContext context, int w, int h) { var pixels = context.Pixels; // Determine distances between controls points (bounding rect) to find the optimal stepsize var minX = Math.Min(x1, Math.Min(x2, Math.Min(x3, x4))); var minY = Math.Min(y1, Math.Min(y2, Math.Min(y3, y4))); var maxX = Math.Max(x1, Math.Max(x2, Math.Max(x3, x4))); var maxY = Math.Max(y1, Math.Max(y2, Math.Max(y3, y4))); // Get slope var lenx = maxX - minX; var len = maxY - minY; if (lenx > len) { len = lenx; } // Prevent divison by zero var list = new List<int>(); if (len != 0) { // Init vars var step = StepFactor / len; // Calculate factors var sx1 = tension * (x3 - x1); var sy1 = tension * (y3 - y1); var sx2 = tension * (x4 - x2); var sy2 = tension * (y4 - y2); var ax = sx1 + sx2 + 2 * x2 - 2 * x3; var ay = sy1 + sy2 + 2 * y2 - 2 * y3; var bx = -2 * sx1 - sx2 - 3 * x2 + 3 * x3; var by = -2 * sy1 - sy2 - 3 * y2 + 3 * y3; // Interpolate for (var t = 0f; t <= 1; t += step) { var tSq = t * t; int tx = (int)(ax * tSq * t + bx * tSq + sx1 * t + x2); int ty = (int)(ay * tSq * t + by * tSq + sy1 * t + y2); list.Add(tx); list.Add(ty); } // Prevent rounding gap list.Add(x3); list.Add(y3); } return list; }
private static void Draw(BitmapContext context, int x1, int y1, int x2, int y2, int dotSpace, int dotLength, int color) { // y = m * x + n // y - m * x = n int width = context.Width; int height = context.Height; // Perform cohen-sutherland clipping if either point is out of the viewport if (!CohenSutherlandLineClip(new Rect(0, 0, width, height), ref x1, ref y1, ref x2, ref y2)) { return; } Swap(ref x1, ref x2, ref y1, ref y2); float m = (y2 - y1) / (float)(x2 - x1); float n = y1 - m * x1; var pixels = context.Pixels; bool on = true; int spaceCnt = 0; for (int i = x1; i <= width; i++) { if (i == 0) { continue; } int y = (int)(m * i + n); if (y <= 0) { continue; } if (y >= height || i >= x2) { continue; } if (on) { //bmp.SetPixel(i, y, color); //var idx = GetIndex(i, y, width); var idx = (y - 1) * width + i - 1; pixels[idx] = color; spaceCnt = 0; on = i % dotLength != 0; } else { spaceCnt++; on = spaceCnt % dotSpace == 0; } } }
/// <summary> /// Draws a segment of a Cardinal spline (cubic) defined by four control points. /// </summary> /// <param name="x1">The x-coordinate of the 1st control point.</param> /// <param name="y1">The y-coordinate of the 1st control point.</param> /// <param name="x2">The x-coordinate of the 2nd control point.</param> /// <param name="y2">The y-coordinate of the 2nd control point.</param> /// <param name="x3">The x-coordinate of the 3rd control point.</param> /// <param name="y3">The y-coordinate of the 3rd control point.</param> /// <param name="x4">The x-coordinate of the 4th control point.</param> /// <param name="y4">The y-coordinate of the 4th control point.</param> /// <param name="tension">The tension of the curve defines the shape. Usually between 0 and 1. 0 would be a straight line.</param> /// <param name="color">The color.</param> /// <param name="context">The pixel context.</param> /// <param name="w">The width of the bitmap.</param> /// <param name="h">The height of the bitmap.</param> private static void DrawCurveSegment(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, float tension, int color, BitmapContext context, int w, int h) { // Determine distances between controls points (bounding rect) to find the optimal stepsize var minX = Math.Min(x1, Math.Min(x2, Math.Min(x3, x4))); var minY = Math.Min(y1, Math.Min(y2, Math.Min(y3, y4))); var maxX = Math.Max(x1, Math.Max(x2, Math.Max(x3, x4))); var maxY = Math.Max(y1, Math.Max(y2, Math.Max(y3, y4))); // Get slope var lenx = maxX - minX; var len = maxY - minY; if (lenx > len) { len = lenx; } // Prevent divison by zero if (len != 0) { // Init vars var step = StepFactor / len; int tx1 = x2; int ty1 = y2; int tx2, ty2; // Calculate factors var sx1 = tension * (x3 - x1); var sy1 = tension * (y3 - y1); var sx2 = tension * (x4 - x2); var sy2 = tension * (y4 - y2); var ax = sx1 + sx2 + (2 * x2) - (2 * x3); var ay = sy1 + sy2 + (2 * y2) - (2 * y3); var bx = (-2 * sx1) - sx2 - (3 * x2) + (3 * x3); var by = (-2 * sy1) - sy2 - (3 * y2) + (3 * y3); // Interpolate for (var t = step; t <= 1; t += step) { var tSq = t * t; tx2 = (int)((ax * tSq * t) + (bx * tSq) + (sx1 * t) + x2); ty2 = (int)((ay * tSq * t) + (by * tSq) + (sy1 * t) + y2); // Draw line DrawLine(context, w, h, tx1, ty1, tx2, ty2, color); tx1 = tx2; ty1 = ty2; } // Prevent rounding gap DrawLine(context, w, h, tx1, ty1, x3, y3, color); } }
public static void Blit(BitmapContext destContext, int dpw, int dph, Rect destRect, BitmapContext srcContext, Rect sourceRect, int sourceWidth) { const BlendMode blendMode = BlendMode.Alpha; int dw = (int)destRect.Width; int dh = (int)destRect.Height; Rect intersect = new Rect(0, 0, dpw, dph); intersect.Intersect(destRect); if (intersect.IsEmpty) { return; } #if WPF var isPrgba = srcContext.Format == PixelFormats.Pbgra32 || srcContext.Format == PixelFormats.Prgba64 || srcContext.Format == PixelFormats.Prgba128Float; #endif var sourcePixels = srcContext.Pixels; var destPixels = destContext.Pixels; int sourceLength = srcContext.Length; int sourceIdx = -1; int px = (int)destRect.X; int py = (int)destRect.Y; int x; int y; int idx; double ii; double jj; int sr = 0; int sg = 0; int sb = 0; int dr, dg, db; int sourcePixel; int sa = 0; int da; var sw = (int)sourceRect.Width; var sdx = sourceRect.Width / destRect.Width; var sdy = sourceRect.Height / destRect.Height; int sourceStartX = (int)sourceRect.X; int sourceStartY = (int)sourceRect.Y; int lastii, lastjj; lastii = -1; lastjj = -1; jj = sourceStartY; y = py; for (var j = 0; j < dh; j++) { if (y >= 0 && y < dph) { ii = sourceStartX; idx = px + y * dpw; x = px; sourcePixel = sourcePixels[0]; // Pixel by pixel copying for (var i = 0; i < dw; i++) { if (x >= 0 && x < dpw) { if ((int)ii != lastii || (int)jj != lastjj) { sourceIdx = (int)ii + (int)jj * sourceWidth; if (sourceIdx >= 0 && sourceIdx < sourceLength) { sourcePixel = sourcePixels[sourceIdx]; sa = ((sourcePixel >> 24) & 0xff); sr = ((sourcePixel >> 16) & 0xff); sg = ((sourcePixel >> 8) & 0xff); sb = ((sourcePixel) & 0xff); } else { sa = 0; } } if (sa > 0) { int destPixel = destPixels[idx]; da = ((destPixel >> 24) & 0xff); if ((sa == 255 || da == 0)) { destPixels[idx] = sourcePixel; } else { dr = ((destPixel >> 16) & 0xff); dg = ((destPixel >> 8) & 0xff); db = ((destPixel) & 0xff); var isa = 255 - sa; #if NETFX_CORE // Special case for WinRT since it does not use pARGB (pre-multiplied alpha) destPixel = ((da & 0xff) << 24) | ((((sr * sa + isa * dr) >> 8) & 0xff) << 16) | ((((sg * sa + isa * dg) >> 8) & 0xff) << 8) | (((sb * sa + isa * db) >> 8) & 0xff); #elif WPF if (isPrgba) { destPixel = ((da & 0xff) << 24) | (((((sr << 8) + isa * dr) >> 8) & 0xff) << 16) | (((((sg << 8) + isa * dg) >> 8) & 0xff) << 8) | ((((sb << 8) + isa * db) >> 8) & 0xff); } else { destPixel = ((da & 0xff) << 24) | (((((sr * sa) + isa * dr) >> 8) & 0xff) << 16) | (((((sg * sa) + isa * dg) >> 8) & 0xff) << 8) | ((((sb * sa) + isa * db) >> 8) & 0xff); } #else destPixel = ((da & 0xff) << 24) | (((((sr << 8) + isa * dr) >> 8) & 0xff) << 16) | (((((sg << 8) + isa * dg) >> 8) & 0xff) << 8) | ((((sb << 8) + isa * db) >> 8) & 0xff); #endif destPixels[idx] = destPixel; } } } x++; idx++; ii += sdx; } } jj += sdy; y++; } }
/// <summary> /// Copies (blits) the pixels from the WriteableBitmap source to the destination WriteableBitmap (this). /// </summary> /// <param name="bmp">The destination WriteableBitmap.</param> /// <param name="destRect">The rectangle that defines the destination region.</param> /// <param name="source">The source WriteableBitmap.</param> /// <param name="sourceRect">The rectangle that will be copied from the source to the destination.</param> /// <param name="color">If not Colors.White, will tint the source image. A partially transparent color and the image will be drawn partially transparent. If the BlendMode is ColorKeying, this color will be used as color key to mask all pixels with this value out.</param> /// <param name="blendMode">The blending mode <see cref="BlendMode"/>.</param> internal static void Blit(this WriteableBitmap bmp, Rect destRect, WriteableBitmap source, Rect sourceRect, Color color, BlendMode blendMode) { if (color.A == 0) { return; } #if WPF var isPrgba = source.Format == PixelFormats.Pbgra32 || source.Format == PixelFormats.Prgba64 || source.Format == PixelFormats.Prgba128Float; #endif var dw = (int)destRect.Width; var dh = (int)destRect.Height; using (var srcContext = source.GetBitmapContext(ReadWriteMode.ReadOnly)) { using (var destContext = bmp.GetBitmapContext()) { var sourceWidth = srcContext.Width; var dpw = destContext.Width; var dph = destContext.Height; var intersect = new Rect(0, 0, dpw, dph); intersect.Intersect(destRect); if (intersect.IsEmpty) { return; } var sourcePixels = srcContext.Pixels; var destPixels = destContext.Pixels; var sourceLength = srcContext.Length; int sourceIdx = -1; int px = (int)destRect.X; int py = (int)destRect.Y; int x; int y; int idx; double ii; double jj; int sr = 0; int sg = 0; int sb = 0; int dr, dg, db; int sourcePixel; int sa = 0; int da; int ca = color.A; int cr = color.R; int cg = color.G; int cb = color.B; bool tinted = color != Colors.White; var sw = (int)sourceRect.Width; var sdx = sourceRect.Width / destRect.Width; var sdy = sourceRect.Height / destRect.Height; int sourceStartX = (int)sourceRect.X; int sourceStartY = (int)sourceRect.Y; int lastii, lastjj; lastii = -1; lastjj = -1; jj = sourceStartY; y = py; for (int j = 0; j < dh; j++) { if (y >= 0 && y < dph) { ii = sourceStartX; idx = px + (y * dpw); x = px; sourcePixel = sourcePixels[0]; // Scanline BlockCopy is much faster (3.5x) if no tinting and blending is needed, // even for smaller sprites like the 32x32 particles. if (blendMode == BlendMode.None && !tinted) { sourceIdx = (int)ii + ((int)jj * sourceWidth); var offset = x < 0 ? -x : 0; var xx = x + offset; var wx = sourceWidth - offset; var len = xx + wx < dpw ? wx : dpw - xx; if (len > sw) { len = sw; } if (len > dw) { len = dw; } BitmapContext.BlockCopy(srcContext, (sourceIdx + offset) * 4, destContext, (idx + offset) * 4, len * 4); } // Pixel by pixel copying else { for (int i = 0; i < dw; i++) { if (x >= 0 && x < dpw) { if ((int)ii != lastii || (int)jj != lastjj) { sourceIdx = (int)ii + ((int)jj * sourceWidth); if (sourceIdx >= 0 && sourceIdx < sourceLength) { sourcePixel = sourcePixels[sourceIdx]; sa = (sourcePixel >> 24) & 0xff; sr = (sourcePixel >> 16) & 0xff; sg = (sourcePixel >> 8) & 0xff; sb = (sourcePixel) & 0xff; if (tinted && sa != 0) { sa = (sa * ca * 0x8081) >> 23; sr = (((sr * cr * 0x8081) >> 23) * ca * 0x8081) >> 23; sg = (((sg * cg * 0x8081) >> 23) * ca * 0x8081) >> 23; sb = (((sb * cb * 0x8081) >> 23) * ca * 0x8081) >> 23; sourcePixel = (sa << 24) | (sr << 16) | (sg << 8) | sb; } } else { sa = 0; } } if (blendMode == BlendMode.None) { destPixels[idx] = sourcePixel; } else if (blendMode == BlendMode.ColorKeying) { sr = (sourcePixel >> 16) & 0xff; sg = (sourcePixel >> 8) & 0xff; sb = (sourcePixel) & 0xff; if (sr != color.R || sg != color.G || sb != color.B) { destPixels[idx] = sourcePixel; } } else if (blendMode == BlendMode.Mask) { int destPixel = destPixels[idx]; da = (destPixel >> 24) & 0xff; dr = (destPixel >> 16) & 0xff; dg = (destPixel >> 8) & 0xff; db = (destPixel) & 0xff; destPixel = (((da * sa * 0x8081) >> 23) << 24) | (((dr * sa * 0x8081) >> 23) << 16) | (((dg * sa * 0x8081) >> 23) << 8) | ((db * sa * 0x8081) >> 23); destPixels[idx] = destPixel; } else if (sa > 0) { int destPixel = destPixels[idx]; da = (destPixel >> 24) & 0xff; if ((sa == 255 || da == 0) && blendMode != BlendMode.Additive && blendMode != BlendMode.Subtractive && blendMode != BlendMode.Multiply) { destPixels[idx] = sourcePixel; } else { dr = (destPixel >> 16) & 0xff; dg = (destPixel >> 8) & 0xff; db = (destPixel) & 0xff; if (blendMode == BlendMode.Alpha) { var isa = 255 - sa; #if NETFX_CORE // Special case for WinRT since it does not use pARGB (pre-multiplied alpha) destPixel = ((da & 0xff) << 24) | ((((sr * sa + isa * dr) >> 8) & 0xff) << 16) | ((((sg * sa + isa * dg) >> 8) & 0xff) << 8) | (((sb * sa + isa * db) >> 8) & 0xff); #elif WPF if (isPrgba) { destPixel = ((da & 0xff) << 24) | (((((sr << 8) + isa * dr) >> 8) & 0xff) << 16) | (((((sg << 8) + isa * dg) >> 8) & 0xff) << 8) | ((((sb << 8) + isa * db) >> 8) & 0xff); } else { destPixel = ((da & 0xff) << 24) | (((((sr * sa) + isa * dr) >> 8) & 0xff) << 16) | (((((sg * sa) + isa * dg) >> 8) & 0xff) << 8) | ((((sb * sa) + isa * db) >> 8) & 0xff); } #else destPixel = ((da & 0xff) << 24) | (((((sr << 8) + (isa * dr)) >> 8) & 0xff) << 16) | (((((sg << 8) + (isa * dg)) >> 8) & 0xff) << 8) | ((((sb << 8) + (isa * db)) >> 8) & 0xff); #endif } else if (blendMode == BlendMode.Additive) { int a = (255 <= sa + da) ? 255 : (sa + da); destPixel = (a << 24) | (((a <= sr + dr) ? a : (sr + dr)) << 16) | (((a <= sg + dg) ? a : (sg + dg)) << 8) | ((a <= sb + db) ? a : (sb + db)); } else if (blendMode == BlendMode.Subtractive) { int a = da; destPixel = (a << 24) | (((sr >= dr) ? 0 : (sr - dr)) << 16) | (((sg >= dg) ? 0 : (sg - dg)) << 8) | ((sb >= db) ? 0 : (sb - db)); } else if (blendMode == BlendMode.Multiply) { // Faster than a division like (s * d) / 255 are 2 shifts and 2 adds int ta = (sa * da) + 128; int tr = (sr * dr) + 128; int tg = (sg * dg) + 128; int tb = (sb * db) + 128; int ba = ((ta >> 8) + ta) >> 8; int br = ((tr >> 8) + tr) >> 8; int bg = ((tg >> 8) + tg) >> 8; int bb = ((tb >> 8) + tb) >> 8; destPixel = (ba << 24) | ((ba <= br ? ba : br) << 16) | ((ba <= bg ? ba : bg) << 8) | (ba <= bb ? ba : bb); } destPixels[idx] = destPixel; } } } x++; idx++; ii += sdx; } } } jj += sdy; y++; } } } }
/// <summary> /// Blends a specific source color on top of a destination premultiplied color /// </summary> /// <param name="context">Array containing destination color</param> /// <param name="index">Index of destination pixel</param> /// <param name="sa">Source alpha (0..255)</param> /// <param name="srb">Source non-premultiplied red and blue component in the format 0x00rr00bb</param> /// <param name="sg">Source green component (0..255)</param> private static void AlphaBlendNormalOnPremultiplied(BitmapContext context, int index, int sa, uint srb, uint sg) { var pixels = context.Pixels; var destPixel = (uint)pixels[index]; var da = (destPixel >> 24); var dg = ((destPixel >> 8) & 0xff); var drb = destPixel & 0x00FF00FF; // blend with high-quality alpha and lower quality but faster 1-off RGBs pixels[index] = (int)( ((sa + ((da * (255 - sa) * 0x8081) >> 23)) << 24) | // alpha (((sg - dg) * sa + (dg << 8)) & 0xFFFFFF00) | // green (((((srb - drb) * sa) >> 8) + drb) & 0x00FF00FF) // red and blue ); }
public static void Blit(BitmapContext destContext, int dpw, int dph, Rect destRect, BitmapContext srcContext, Rect sourceRect, int sourceWidth) { const BlendMode blendMode = BlendMode.Alpha; int dw = (int)destRect.Width; int dh = (int)destRect.Height; Rect intersect = new Rect(0, 0, dpw, dph); intersect.Intersect(destRect); if (intersect.IsEmpty) { return; } #if WPF var isPrgba = srcContext.Format == PixelFormats.Pbgra32 || srcContext.Format == PixelFormats.Prgba64 || srcContext.Format == PixelFormats.Prgba128Float; #endif var sourcePixels = srcContext.Pixels; var destPixels = destContext.Pixels; int sourceLength = srcContext.Length; int sourceIdx = -1; int px = (int)destRect.X; int py = (int)destRect.Y; int x; int y; int idx; double ii; double jj; int sr = 0; int sg = 0; int sb = 0; int dr, dg, db; int sourcePixel; int sa = 0; int da; var sw = (int)sourceRect.Width; var sdx = sourceRect.Width / destRect.Width; var sdy = sourceRect.Height / destRect.Height; int sourceStartX = (int)sourceRect.X; int sourceStartY = (int)sourceRect.Y; int lastii, lastjj; lastii = -1; lastjj = -1; jj = sourceStartY; y = py; for (var j = 0; j < dh; j++) { if (y >= 0 && y < dph) { ii = sourceStartX; idx = px + (y * dpw); x = px; sourcePixel = sourcePixels[0]; // Pixel by pixel copying for (var i = 0; i < dw; i++) { if (x >= 0 && x < dpw) { if ((int)ii != lastii || (int)jj != lastjj) { sourceIdx = (int)ii + ((int)jj * sourceWidth); if (sourceIdx >= 0 && sourceIdx < sourceLength) { sourcePixel = sourcePixels[sourceIdx]; sa = (sourcePixel >> 24) & 0xff; sr = (sourcePixel >> 16) & 0xff; sg = (sourcePixel >> 8) & 0xff; sb = (sourcePixel) & 0xff; } else { sa = 0; } } if (sa > 0) { int destPixel = destPixels[idx]; da = (destPixel >> 24) & 0xff; if (sa == 255 || da == 0) { destPixels[idx] = sourcePixel; } else { dr = (destPixel >> 16) & 0xff; dg = (destPixel >> 8) & 0xff; db = (destPixel) & 0xff; var isa = 255 - sa; #if NETFX_CORE // Special case for WinRT since it does not use pARGB (pre-multiplied alpha) destPixel = ((da & 0xff) << 24) | ((((sr * sa + isa * dr) >> 8) & 0xff) << 16) | ((((sg * sa + isa * dg) >> 8) & 0xff) << 8) | (((sb * sa + isa * db) >> 8) & 0xff); #elif WPF if (isPrgba) { destPixel = ((da & 0xff) << 24) | (((((sr << 8) + isa * dr) >> 8) & 0xff) << 16) | (((((sg << 8) + isa * dg) >> 8) & 0xff) << 8) | ((((sb << 8) + isa * db) >> 8) & 0xff); } else { destPixel = ((da & 0xff) << 24) | (((((sr * sa) + isa * dr) >> 8) & 0xff) << 16) | (((((sg * sa) + isa * dg) >> 8) & 0xff) << 8) | ((((sb * sa) + isa * db) >> 8) & 0xff); } #else destPixel = ((da & 0xff) << 24) | (((((sr << 8) + (isa * dr)) >> 8) & 0xff) << 16) | (((((sg << 8) + (isa * dg)) >> 8) & 0xff) << 8) | ((((sb << 8) + (isa * db)) >> 8) & 0xff); #endif destPixels[idx] = destPixel; } } } x++; idx++; ii += sdx; } } jj += sdy; y++; } }
/// <summary> /// Draws a line using a pen / stamp for the line /// </summary> /// <param name="context">The context containing the pixels as int RGBA value.</param> /// <param name="w">The width of one scanline in the pixels array.</param> /// <param name="h">The height of the bitmap.</param> /// <param name="x1">The x-coordinate of the start point.</param> /// <param name="y1">The y-coordinate of the start point.</param> /// <param name="x2">The x-coordinate of the end point.</param> /// <param name="y2">The y-coordinate of the end point.</param> /// <param name="pen">The pen context.</param> public static void DrawLinePenned(BitmapContext context, int w, int h, int x1, int y1, int x2, int y2, BitmapContext pen) { // Edge case where lines that went out of vertical bounds clipped instead of disappearing if((y1 < 0 && y2 < 0) || (y1 > h && y2 > h)) return; if (x1 == x2 && y1 == y2) return; // Perform cohen-sutherland clipping if either point is out of the viewport if (!CohenSutherlandLineClip(new Rect(0, 0, w, h), ref x1, ref y1, ref x2, ref y2)) return; int size = pen.WriteableBitmap.PixelWidth; int pw = size; var srcRect = new Rect(0, 0, size, size); // Distance start and end point int dx = x2 - x1; int dy = y2 - y1; // Determine sign for direction x int incx = 0; if (dx < 0) { dx = -dx; incx = -1; } else if (dx > 0) { incx = 1; } // Determine sign for direction y int incy = 0; if (dy < 0) { dy = -dy; incy = -1; } else if (dy > 0) { incy = 1; } // Which gradient is larger int pdx, pdy, odx, ody, es, el; if (dx > dy) { pdx = incx; pdy = 0; odx = incx; ody = incy; es = dy; el = dx; } else { pdx = 0; pdy = incy; odx = incx; ody = incy; es = dx; el = dy; } // Init start int x = x1; int y = y1; int error = el >> 1; var destRect = new Rect(x, y, size, size); if (y < h && y >= 0 && x < w && x >= 0) { //Blit(context.WriteableBitmap, new Rect(x,y,3,3), pen.WriteableBitmap, new Rect(0,0,3,3)); Blit(context, w, h, destRect, pen, srcRect, pw); //pixels[y * w + x] = color; } // Walk the line! for (int i = 0; i < el; i++) { // Update error term error -= es; // Decide which coord to use if (error < 0) { error += el; x += odx; y += ody; } else { x += pdx; y += pdy; } // Set pixel if (y < h && y >= 0 && x < w && x >= 0) { //Blit(context, w, h, destRect, pen, srcRect, pw); Blit(context, w, h, new Rect(x, y, size, size), pen, srcRect, pw); //Blit(context.WriteableBitmap, destRect, pen.WriteableBitmap, srcRect); //pixels[y * w + x] = color; } } }
/// <summary> /// Creates a new resized bitmap. /// </summary> /// <param name="srcContext">The source context.</param> /// <param name="widthSource">The width of the source pixels.</param> /// <param name="heightSource">The height of the source pixels.</param> /// <param name="width">The new desired width.</param> /// <param name="height">The new desired height.</param> /// <param name="interpolation">The interpolation method that should be used.</param> /// <returns>A new bitmap that is a resized version of the input.</returns> public static int[] Resize(BitmapContext srcContext, int widthSource, int heightSource, int width, int height, Interpolation interpolation) { return(Resize(srcContext.Pixels, widthSource, heightSource, width, height, interpolation)); }
/// <summary> /// Draws an anti-aliased line with a desired stroke thickness /// <param name="context">The context containing the pixels as int RGBA value.</param> /// <param name="x1">The x-coordinate of the start point.</param> /// <param name="y1">The y-coordinate of the start point.</param> /// <param name="x2">The x-coordinate of the end point.</param> /// <param name="y2">The y-coordinate of the end point.</param> /// <param name="color">The color for the line.</param> /// <param name="strokeThickness">The stroke thickness of the line.</param> /// </summary> public static void DrawLineAa(BitmapContext context, int pixelWidth, int pixelHeight, int x1, int y1, int x2, int y2, Color color, int strokeThickness) { var col = ConvertColor(color); AAWidthLine(pixelWidth, pixelHeight, context, x1, y1, x2, y2, strokeThickness, col); }
/// <summary> /// Performs a Copy operation from source Array to destination BitmapContext /// </summary> /// <remarks>Equivalent to calling Buffer.BlockCopy in Silverlight, or native memcpy in WPF</remarks> public static void BlockCopy(Array src, int srcOffset, BitmapContext dest, int destOffset, int count) { Buffer.BlockCopy(src, srcOffset, dest.Pixels, destOffset, count); }
public BitmapRenderer(LWF lwf, BitmapContext context) : base(lwf) { m_context = context; m_matrix = new Matrix(0, 0, 0, 0, 0, 0); m_matrixForRender = new Matrix4x4(); m_colorMult = new UnityEngine.Color(); m_colorAdd = new UnityEngine.Color(); m_blendMode = (int)Format.Constant.BLEND_MODE_NORMAL; m_z = -1; m_updated = false; m_buffer = null; m_bufferIndex = -1; }
public BitmapRenderer(LWF lwf, BitmapContext context) : base(lwf) { m_context = context; m_matrix = new Matrix4x4(); m_colorMult = new UnityEngine.Color(); #if LWF_USE_ADDITIONALCOLOR m_colorAdd = new UnityEngine.Color(); #endif if (m_context != null) m_context.factory.AddBitmap(); }
public BitmapRenderer(LWF lwf, BitmapContext context) : base(lwf) { m_context = context; m_property = new MaterialPropertyBlock(); m_matrix = new Matrix4x4(); m_renderMatrix = new Matrix4x4(); m_colorMult = new UnityEngine.Color(); #if LWF_USE_ADDITIONALCOLOR m_colorAdd = new UnityEngine.Color(); #endif }
public BitmapRenderer(LWF lwf, BitmapContext context) : base(lwf) { m_context = context; m_property = new MaterialPropertyBlock(); m_matrix = new Matrix4x4(); m_renderMatrix = new Matrix4x4(); m_colorMult = new UnityEngine.Color(); m_colorAdd = new UnityEngine.Color(); m_blendMode = (int)Format.Constant.BLEND_MODE_NORMAL; m_colorId = Shader.PropertyToID("_Color"); m_additionalColorId = Shader.PropertyToID("_AdditionalColor"); }
/// <summary> /// Creates a new resized bitmap. /// </summary> /// <param name="srcContext">The source context.</param> /// <param name="widthSource">The width of the source pixels.</param> /// <param name="heightSource">The height of the source pixels.</param> /// <param name="width">The new desired width.</param> /// <param name="height">The new desired height.</param> /// <param name="interpolation">The interpolation method that should be used.</param> /// <returns>A new bitmap that is a resized version of the input.</returns> public static int[] Resize(BitmapContext srcContext, int widthSource, int heightSource, int width, int height, Interpolation interpolation) { return Resize(srcContext.Pixels, widthSource, heightSource, width, height, interpolation); }
/// <summary> /// Performs a Copy operation from source BitmapContext to destination Array /// </summary> /// <remarks>Equivalent to calling Buffer.BlockCopy in Silverlight, or native memcpy in WPF</remarks> public static void BlockCopy(BitmapContext src, int srcOffset, byte[] dest, int destOffset, int count) { Buffer.BlockCopy(src.Pixels, srcOffset, dest, destOffset, count); }