public BitmapSurface(BitmapSurface surface, int width, int height) : this(width, height) { if (BmpSource.PixelFormat != surface.BmpSource.PixelFormat) throw new ArgumentException("У исходной поверхности должен быть тот же формат пикселя"); lock (surface.LockObject) { lock (LockObject) { var count = Math.Min(stride, surface.stride); var lines = Math.Min(Height, surface.Height); var block = lines / Environment.ProcessorCount; Parallel.For(0, Environment.ProcessorCount, (int i) => { var srcptr = surface.ImageBits + surface.stride * block * i - surface.stride; var dstptr = ImageBits + stride * block * i - stride; for (int j = block; j > 0; --j) #if NETFX_46 Buffer.MemoryCopy(srcptr += surface.stride, dstptr += stride, stride, count)); #else MemCpy._memcpy_uu(dstptr += stride, srcptr += surface.stride, count); #endif }); lines -= block * Environment.ProcessorCount; block *= Environment.ProcessorCount; var srclpi = surface.ImageBits + surface.stride * (block - 1); var dstlpi = ImageBits + stride * (block - 1); for (int j = lines; j > 0; --j) #if NETFX_46 Buffer.MemoryCopy(srclpi += surface.stride, dstlpi += stride, stride, count)); #else MemCpy._memcpy_uu(dstlpi += stride, srclpi += surface.stride, count); #endif } } }
private void Initialize(int width, int height) { if (width == _BI.biHeader.bihWidth && height == -_BI.biHeader.bihHeight) return; lock (LockObj) { if (_GFX != null) _GFX.Dispose(); if (_DIB != null) _DIB.Dispose(); _DIB = new BitmapSurface(width, height); _GFX = GDIGraphics.FromImage(_DIB.BmpSource); _GFX.CompositingQuality = _gfxcompq; _GFX.CompositingMode = _gfxcompm; _GFX.SmoothingMode = _gfxsmoth; _DIB.DrawQuality = _dibdmode; _BI = new BITMAPINFO { biHeader = { bihBitCount = 32, bihPlanes = 1, bihSize = 40, bihWidth = +width, bihHeight = -height, bihSizeImage = (width * height) << 2 } }; } }
public static unsafe void FillRectangle(this BitmapSurface surface, int color, int sx, int sy, int width, int height) { unchecked { if (!Drawing.ClipRect(surface.Clipper, ref sx, ref sy, ref width, ref height)) { return; } Drawing.FillRectangle((int *)surface.ImageBits, surface.Width, color, sx, sy, width, height); } }
public static unsafe void DrawLine(this BitmapSurface surface, int color, double x1, double y1, double x2, double y2) { if (!Drawing.Clip2D(surface.Clipper, ref x1, ref y1, ref x2, ref y2)) { return; } if (surface.DrawQuality == SurfaceDrawQuality.High) { Drawing.DrawLineHQ((int *)surface.ImageBits, surface.Width, color, x1, y1, x2, y2); } else { Drawing.DrawLineLQ((int *)surface.ImageBits, surface.Width, color, (int)(x1 + 0.5), (int)(y1 + 0.5), (int)(x2 + 0.5), (int)(y2 + 0.5)); } }
public static unsafe void DrawTriangle(this BitmapSurface surface, int color1, double x1, double y1, int color2, double x2, double y2, int color3, double x3, double y3) { if (surface.Clipper.PointsInBounds(x1, y1, x2, y2, x3, y3)) { Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color1, x1, y1, color2, x2, y2, color3, x3, y3); return; } // NOTE: Отсутсвует реализация частных случаев триангуляции, когда две или три грани полностью отсекаются // Соотношение старых и новых координат после отсечения: // // (_x1,_y1) // O 1 // / \ // (x0,y0) / \ (x1,y1) // --+-----+-- // \ / \ / // (x2,y2) + + (x3,y3) // / \ / \ // 2 / \ / \ 3 // (_x2,_y2) O ----+---+---- O (_x3,_y3) // (x4,y4)\ /(x5,y5) int trimed; double _x1 = x1, _y1 = y1, _x2 = x2, _y2 = y2, _x3 = x3, _y3 = y3; double x0 = x1, y0 = y1, x4 = x2, y4 = y2, x5 = x3, y5 = y3; if (!Drawing.Clip2D(surface.Clipper, ref x0, ref y0, ref x2, ref y2)) { if (!Drawing.Clip2D(surface.Clipper, ref x1, ref y1, ref x3, ref y3)) { if (!Drawing.Clip2D(surface.Clipper, ref x4, ref y4, ref x5, ref y5)) { return; // все грани не определены } else { return; // грани 1-2 и 1-3 не определены } } else if (!Drawing.Clip2D(surface.Clipper, ref x4, ref y4, ref x5, ref y5)) { return; // грани 1-2 и 2-3 не определены } else { x0 = x1; y0 = y1; x2 = x4; y2 = y4; trimed = ((x3 == _x3 && y3 == _y3 && x5 == _x3 && y5 == _y3) ? 11 : 15); } } else if (!Drawing.Clip2D(surface.Clipper, ref x1, ref y1, ref x3, ref y3)) { if (!Drawing.Clip2D(surface.Clipper, ref x4, ref y4, ref x5, ref y5)) { return; // грани 1-3 и 2-3 не определены } else { x1 = x0; y1 = y0; x3 = x5; y3 = y5; trimed = ((x2 == _x2 && y2 == _y2 && x4 == _x2 && y4 == _y2) ? 13 : 15); } } else if (!Drawing.Clip2D(surface.Clipper, ref x4, ref y4, ref x5, ref y5)) { x4 = x2; y4 = y2; x5 = x3; y5 = y3; trimed = ((x0 == _x1 && y0 == _y1 && x1 == _x1 && y1 == _y1) ? 14 : 15); } else { trimed = ((x0 == _x1 && y0 == _y1 && x1 == _x1 && y1 == _y1) ? 0 : 1) | ((x2 == _x2 && y2 == _y2 && x4 == _x2 && y4 == _y2) ? 0 : 2) | ((x3 == _x3 && y3 == _y3 && x5 == _x3 && y5 == _y3) ? 0 : 4); } int c0, c1, c2, c3, c4, c5; Drawing.FColor _c1 = color1, _c2 = color2, _c3 = color3; if ((trimed & 3) != 0) { var cd = (_c2 - _c1) / (float)Math.Sqrt((_x2 - _x1) * (_x2 - _x1) + (_y2 - _y1) * (_y2 - _y1)); c0 = _c1 + cd * (float)Math.Sqrt((x0 - _x1) * (x0 - _x1) + (y0 - _y1) * (y0 - _y1)); c2 = _c1 + cd * (float)Math.Sqrt((x2 - _x1) * (x2 - _x1) + (y2 - _y1) * (y2 - _y1)); } else { c0 = color1; c2 = color2; } if ((trimed & 5) != 0) { var cd = (_c3 - _c1) / (float)Math.Sqrt((_x3 - _x1) * (_x3 - _x1) + (_y3 - _y1) * (_y3 - _y1)); c1 = _c1 + cd * (float)Math.Sqrt((x1 - _x1) * (x1 - _x1) + (y1 - _y1) * (y1 - _y1)); c3 = _c1 + cd * (float)Math.Sqrt((x3 - _x1) * (x3 - _x1) + (y3 - _y1) * (y3 - _y1)); } else { c1 = color1; c3 = color3; } if ((trimed & 6) != 0) { var cd = (_c3 - _c2) / (float)Math.Sqrt((_x3 - _x2) * (_x3 - _x2) + (_y3 - _y2) * (_y3 - _y2)); c4 = _c2 + cd * (float)Math.Sqrt((x4 - _x2) * (x4 - _x2) + (y4 - _y2) * (y4 - _y2)); c5 = _c2 + cd * (float)Math.Sqrt((x5 - _x2) * (x5 - _x2) + (y5 - _y2) * (y5 - _y2)); } else { c4 = color2; c5 = color3; } switch (trimed) { case 11: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color3, x3, y3, c1, x1, y1, c4, x4, y4); return; case 13: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color2, x2, y2, c0, x0, y0, c5, x5, y5); return; case 14: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color1, x1, y1, c2, x2, y2, c3, x3, y3); return; case 1: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color2, x2, y2, color3, x3, y3, c0, x0, y0); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color3, x3, y3, c0, x0, y0, c1, x1, y1); return; case 2: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color1, x1, y1, color3, x3, y3, c4, x4, y4); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color1, x1, y1, c4, x4, y4, c2, x2, y2); return; case 4: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color1, x1, y1, color2, x2, y2, c3, x3, y3); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color2, x2, y2, c3, x3, y3, c5, x5, y5); return; case 3: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color3, x3, y3, c1, x1, y1, c0, x0, y0); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color3, x3, y3, c0, x0, y0, c2, x2, y2); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color3, x3, y3, c2, x2, y2, c4, x4, y4); return; case 5: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color2, x2, y2, c0, x0, y0, c1, x1, y1); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color2, x2, y2, c1, x1, y1, c3, x3, y3); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color2, x2, y2, c3, x3, y3, c5, x5, y5); return; case 6: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color1, x1, y1, c2, x2, y2, c4, x4, y4); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color1, x1, y1, c4, x4, y4, c5, x5, y5); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color1, x1, y1, c5, x5, y5, c3, x3, y3); return; case 15: case 7: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, c0, x0, y0, c1, x1, y1, c3, x3, y3); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, c0, x0, y0, c2, x2, y2, c4, x4, y4); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, c0, x0, y0, c3, x3, y3, c5, x5, y5); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, c0, x0, y0, c4, x4, y4, c5, x5, y5); return; default: throw new NotImplementedException(); } }
public static void DrawTriangle(this BitmapSurface surface, int color, DVector2 p1, DVector2 p2, DVector2 p3) { unchecked { DrawTriangle(surface, color, p1.X, p1.Y, p2.X, p2.Y, p3.X, p3.Y); } }
public static unsafe void DrawTriangle(this BitmapSurface surface, int color, double x1, double y1, double x2, double y2, double x3, double y3) { unchecked { if (surface.Clipper.PointsInBounds(x1, y1, x2, y2, x3, y3)) { Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x1, y1, x2, y2, x3, y3); return; } // NOTE: Отсутсвует реализация частных случаев триангуляции, когда две или три грани полностью отсекаются // Соотношение старых и новых координат после отсечения: // // (_x1,_y1) // O 1 // / \ // (x0,y0) / \ (x1,y1) // --+-----+-- // \ / \ / // (x2,y2) + + (x3,y3) // / \ / \ // 2 / \ / \ 3 // (_x2,_y2) O ----+---+---- O (_x3,_y3) // (x4,y4)\ /(x5,y5) int trimed; double _x1 = x1, _y1 = y1, _x2 = x2, _y2 = y2, _x3 = x3, _y3 = y3; double x0 = x1, y0 = y1, x4 = x2, y4 = y2, x5 = x3, y5 = y3; if (!Drawing.Clip2D(surface.Clipper, ref x0, ref y0, ref x2, ref y2)) { if (!Drawing.Clip2D(surface.Clipper, ref x1, ref y1, ref x3, ref y3)) { if (!Drawing.Clip2D(surface.Clipper, ref x4, ref y4, ref x5, ref y5)) { return; // все грани не определены } else { return; // грани 1-2 и 1-3 не определены } } else if (!Drawing.Clip2D(surface.Clipper, ref x4, ref y4, ref x5, ref y5)) { return; // грани 1-2 и 2-3 не определены } else { x0 = x1; y0 = y1; x2 = x4; y2 = y4; trimed = ((x3 == _x3 && y3 == _y3 && x5 == _x3 && y5 == _y3) ? 11 : 15); } } else if (!Drawing.Clip2D(surface.Clipper, ref x1, ref y1, ref x3, ref y3)) { if (!Drawing.Clip2D(surface.Clipper, ref x4, ref y4, ref x5, ref y5)) { return; // грани 1-3 и 2-3 не определены } else { x1 = x0; y1 = y0; x3 = x5; y3 = y5; trimed = ((x2 == _x2 && y2 == _y2 && x4 == _x2 && y4 == _y2) ? 13 : 15); } } else if (!Drawing.Clip2D(surface.Clipper, ref x4, ref y4, ref x5, ref y5)) { x4 = x2; y4 = y2; x5 = x3; y5 = y3; trimed = ((x0 == _x1 && y0 == _y1 && x1 == _x1 && y1 == _y1) ? 14 : 15); } else { trimed = ((x0 == _x1 && y0 == _y1 && x1 == _x1 && y1 == _y1) ? 0 : 1) | ((x2 == _x2 && y2 == _y2 && x4 == _x2 && y4 == _y2) ? 0 : 2) | ((x3 == _x3 && y3 == _y3 && x5 == _x3 && y5 == _y3) ? 0 : 4); } switch (trimed) { case 11: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x3, y3, x1, y1, x4, y4); return; case 13: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x2, y2, x0, y0, x5, y5); return; case 14: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x1, y1, x2, y2, x3, y3); return; case 1: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x2, y2, x3, y3, x0, y0); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x3, y3, x0, y0, x1, y1); return; case 2: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x1, y1, x3, y3, x4, y4); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x1, y1, x4, y4, x2, y2); return; case 4: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x1, y1, x2, y2, x3, y3); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x2, y2, x3, y3, x5, y5); return; case 3: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x3, y3, x1, y1, x0, y0); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x3, y3, x0, y0, x2, y2); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x3, y3, x2, y2, x4, y4); return; case 5: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x2, y2, x0, y0, x1, y1); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x2, y2, x1, y1, x3, y3); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x2, y2, x3, y3, x5, y5); return; case 6: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x1, y1, x2, y2, x4, y4); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x1, y1, x4, y4, x5, y5); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x1, y1, x5, y5, x3, y3); return; case 15: case 7: Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x0, y0, x1, y1, x3, y3); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x0, y0, x2, y2, x4, y4); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x0, y0, x3, y3, x5, y5); Drawing.DrawTriangleLQ((int *)surface.ImageBits, surface.Width, color, x0, y0, x4, y4, x5, y5); return; default: throw new NotImplementedException(); } } }
public static void DrawLine(this BitmapSurface surface, int color, DVector4 p1, DVector4 p2) { unchecked { DrawLine(surface, color, p1.X, p1.Y, p2.X, p2.Y); } }
public Clipper(BitmapSurface surface) { X1 = Y1 = 0; X2 = surface.Width - 1; Y2 = surface.Height - 1; }