public static void Rectangle(this AggRenderSurface gx, RectInt rect, Color color) { gx.Rectangle(rect.Left, rect.Bottom, rect.Right, rect.Top, color); }
public static void FillRectangle(this AggRenderSurface gx, RectInt rect, Color fillColor) { gx.FillRectangle(rect.Left, rect.Bottom, rect.Right, rect.Top, fillColor); }
public static bool ClipRects(RectInt pBoundingRect, ref RectInt pSourceRect, ref RectInt pDestRect) { // clip off the top so we don't write into random memory if (pDestRect.Top < pBoundingRect.Top) { // This type of clipping only works when we aren't scaling an image... // If we are scaling an image, the source and dest sizes won't match if (pSourceRect.Height != pDestRect.Height) { throw new Exception("source and dest rects must have the same height"); } pSourceRect.Top += pBoundingRect.Top - pDestRect.Top; pDestRect.Top = pBoundingRect.Top; if (pDestRect.Top >= pDestRect.Bottom) { return(false); } } // clip off the bottom if (pDestRect.Bottom > pBoundingRect.Bottom) { // This type of clipping only works when we arenst scaling an image... // If we are scaling an image, the source and desst sizes won't match if (pSourceRect.Height != pDestRect.Height) { throw new Exception("source and dest rects must have the same height"); } pSourceRect.Bottom -= pDestRect.Bottom - pBoundingRect.Bottom; pDestRect.Bottom = pBoundingRect.Bottom; if (pDestRect.Bottom <= pDestRect.Top) { return(false); } } // clip off the left if (pDestRect.Left < pBoundingRect.Left) { // This type of clipping only works when we aren't scaling an image... // If we are scaling an image, the source and dest sizes won't match if (pSourceRect.Width != pDestRect.Width) { throw new Exception("source and dest rects must have the same width"); } pSourceRect.Left += pBoundingRect.Left - pDestRect.Left; pDestRect.Left = pBoundingRect.Left; if (pDestRect.Left >= pDestRect.Right) { return(false); } } // clip off the right if (pDestRect.Right > pBoundingRect.Right) { // This type of clipping only works when we aren't scaling an image... // If we are scaling an image, the source and dest sizes won't match if (pSourceRect.Width != pDestRect.Width) { throw new Exception("source and dest rects must have the same width"); } pSourceRect.Right -= pDestRect.Right - pBoundingRect.Right; pDestRect.Right = pBoundingRect.Right; if (pDestRect.Right <= pDestRect.Left) { return(false); } } return(true); }
public void Render(IBitmapSrc source, double destX, double destY) { int inScaleX = 1; int inScaleY = 1; int angleRadians = 0; // exit early if the dest and source bounds don't touch. // TODO: <BUG> make this do rotation and scalling RectInt sourceBounds = new RectInt((int)destX, (int)destY, (int)destX + source.Width, (int)destY + source.Height); //sourceBounds.Offset((int)destX, (int)destY); RectInt destBounds = this.destImageReaderWriter.GetBounds(); if (!RectInt.DoIntersect(sourceBounds, destBounds)) { //if (inScaleX != 1 || inScaleY != 1 || angleRadians != 0) //{ // throw new NotImplementedException(); //} return; } double scaleX = inScaleX; double scaleY = inScaleY; Affine graphicsTransform = this.CurrentTransformMatrix; if (!graphicsTransform.IsIdentity()) { if (scaleX != 1 || scaleY != 1 || angleRadians != 0) { throw new NotImplementedException(); } graphicsTransform.Transform(ref destX, ref destY); } #if false // this is an optomization that eliminates the drawing of images that have their alpha set to all 0 (happens with generated images like explosions). MaxAlphaFrameProperty maxAlphaFrameProperty = MaxAlphaFrameProperty::GetMaxAlphaFrameProperty(source); if ((maxAlphaFrameProperty.GetMaxAlpha() * color.A_Byte) / 256 <= ALPHA_CHANNEL_BITS_DIVISOR) { m_OutFinalBlitBounds.SetRect(0, 0, 0, 0); } #endif bool isScale = (scaleX != 1 || scaleY != 1); bool isRotated = false; if (angleRadians != 0 && Math.Abs(angleRadians) >= (0.1 * MathHelper.Tau / 360)) { isRotated = true; } else { angleRadians = 0;//reset very small angle to 0 } //bool IsMipped = false; //double ox, oy; //source.GetOriginOffset(out ox, out oy); bool canUseMipMaps = isScale; if (scaleX > 0.5 || scaleY > 0.5) { canUseMipMaps = false; } bool needSourceResampling = isScale || isRotated;// || destX != (int)destX || destY != (int)destY; VectorToolBox.GetFreeVxs(out VertexStore imgBoundsPath); // this is the fast drawing path if (needSourceResampling) { #if false // if the scalling is small enough the results can be improved by using mip maps if (CanUseMipMaps) { CMipMapFrameProperty *pMipMapFrameProperty = CMipMapFrameProperty::GetMipMapFrameProperty(source); double OldScaleX = scaleX; double OldScaleY = scaleY; const CFrameInterface *pMippedFrame = pMipMapFrameProperty.GetMipMapFrame(ref scaleX, ref scaleY); if (pMippedFrame != source) { IsMipped = true; source = pMippedFrame; sourceOriginOffsetX *= (OldScaleX / scaleX); sourceOriginOffsetY *= (OldScaleY / scaleY); } HotspotOffsetX *= (inScaleX / scaleX); HotspotOffsetY *= (inScaleY / scaleY); } #endif BuildOrgImgRectVxs(source.Width, source.Height, imgBoundsPath); //Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height, // destX, destY, ox, oy, scaleX, scaleY, angleRadians, imgBoundsPath); Affine destRectTransform = CreateAffine(destX, destY, ox, oy, scaleX, scaleY, angleRadians); //TODO: review reusable span generator an interpolator *** var spanInterpolator = new SpanInterpolatorLinear(); // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004] spanInterpolator.Transformer = destRectTransform.CreateInvert(); var imgSpanGen = new ImgSpanGenRGBA_BilinearClip( source, Drawing.Color.Black, spanInterpolator); VectorToolBox.GetFreeVxs(out VertexStore v1); destRectTransform.TransformToVxs(imgBoundsPath, v1); Render(v1, imgSpanGen); VectorToolBox.ReleaseVxs(ref v1); #if false // this is some debug you can enable to visualize the dest bounding box LineFloat(BoundingRect.left, BoundingRect.top, BoundingRect.right, BoundingRect.top, WHITE); LineFloat(BoundingRect.right, BoundingRect.top, BoundingRect.right, BoundingRect.bottom, WHITE); LineFloat(BoundingRect.right, BoundingRect.bottom, BoundingRect.left, BoundingRect.bottom, WHITE); LineFloat(BoundingRect.left, BoundingRect.bottom, BoundingRect.left, BoundingRect.top, WHITE); #endif } else // TODO: this can be even faster if we do not use an intermediate buffer { //Affine destRectTransform = BuildImageBoundsPath( // source.Width, source.Height, // destX, destY, imgBoundsPath); BuildOrgImgRectVxs(source.Width, source.Height, imgBoundsPath); //... Affine destRectTransform = CreateAffine(destX, destY); //TODO: review reusable span generator an interpolator *** var interpolator = new SpanInterpolatorLinear(); // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004] interpolator.Transformer = destRectTransform.CreateInvert(); //we generate image by this imagespan generator ImgSpanGen imgSpanGen = null; switch (source.BitDepth) { case 32: imgSpanGen = new ImgSpanGenRGBA_NN_StepXBy1(source, interpolator); break; //case 8: // imgSpanGen = new ImgSpanGenGray_NNStepXby1(source, interpolator); // break; default: throw new NotImplementedException(); } VectorToolBox.GetFreeVxs(out VertexStore v1); destRectTransform.TransformToVxs(imgBoundsPath, v1); //... Render(v1, imgSpanGen); VectorToolBox.ReleaseVxs(ref v1); // unchecked { destImageChanged++; }; } VectorToolBox.ReleaseVxs(ref imgBoundsPath); }
public void Render(IBitmapSrc source, double destX, double destY, double angleRadians, double inScaleX, double inScaleY) { { // exit early if the dest and source bounds don't touch. // TODO: <BUG> make this do rotation and scalling RectInt sourceBounds = source.GetBounds(); RectInt destBounds = _destBitmapBlender.GetBounds(); sourceBounds.Offset((int)destX, (int)destY); if (!RectInt.DoIntersect(sourceBounds, destBounds)) { if (inScaleX != 1 || inScaleY != 1 || angleRadians != 0) { throw new NotImplementedException(); } return; } } double scaleX = inScaleX; double scaleY = inScaleY; Affine graphicsTransform = this.CurrentTransformMatrix; if (!graphicsTransform.IsIdentity()) { if (scaleX != 1 || scaleY != 1 || angleRadians != 0) { throw new NotImplementedException(); } graphicsTransform.Transform(ref destX, ref destY); } #if false // this is an optomization that eliminates the drawing of images that have their alpha set to all 0 (happens with generated images like explosions). MaxAlphaFrameProperty maxAlphaFrameProperty = MaxAlphaFrameProperty::GetMaxAlphaFrameProperty(source); if ((maxAlphaFrameProperty.GetMaxAlpha() * color.A_Byte) / 256 <= ALPHA_CHANNEL_BITS_DIVISOR) { m_OutFinalBlitBounds.SetRect(0, 0, 0, 0); } #endif bool isScale = (scaleX != 1 || scaleY != 1); bool isRotated = true; if (Math.Abs(angleRadians) < (0.1 * MathHelper.Tau / 360)) { isRotated = false; angleRadians = 0; } //bool IsMipped = false; //double ox, oy; //source.GetOriginOffset(out ox, out oy); bool canUseMipMaps = isScale; if (scaleX > 0.5 || scaleY > 0.5) { canUseMipMaps = false; } bool renderRequriesSourceSampling = isScale || isRotated || destX != (int)destX || destY != (int)destY; using (VxsTemp.Borrow(out var v1, out var imgBoundsPath)) { // this is the fast drawing path if (renderRequriesSourceSampling) { // if the scalling is small enough the results can be improved by using mip maps //if(CanUseMipMaps) //{ // CMipMapFrameProperty* pMipMapFrameProperty = CMipMapFrameProperty::GetMipMapFrameProperty(source); // double OldScaleX = scaleX; // double OldScaleY = scaleY; // const CFrameInterface* pMippedFrame = pMipMapFrameProperty.GetMipMapFrame(ref scaleX, ref scaleY); // if(pMippedFrame != source) // { // IsMipped = true; // source = pMippedFrame; // sourceOriginOffsetX *= (OldScaleX / scaleX); // sourceOriginOffsetY *= (OldScaleY / scaleY); // } // HotspotOffsetX *= (inScaleX / scaleX); // HotspotOffsetY *= (inScaleY / scaleY); //} //Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height, // destX, destY, ox, oy, scaleX, scaleY, angleRadians, imgBoundsPath); //1. BuildOrgImgRectVxs(source.Width, source.Height, imgBoundsPath); //2. Affine destRectTransform = CreateAffine(destX, destY, _ox, _oy, scaleX, scaleY, angleRadians); //TODO: review reusable span generator an interpolator *** // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004] _spanInterpolator.Transformer = destRectTransform.CreateInvert(); _imgSpanGenBilinearClip.BackgroundColor = Drawing.Color.Black; _imgSpanGenBilinearClip.SetInterpolator(_spanInterpolator); _imgSpanGenBilinearClip.SetSrcBitmap(source); destRectTransform.TransformToVxs(imgBoundsPath, v1); Render(v1, _imgSpanGenBilinearClip); _imgSpanGenBilinearClip.ReleaseSrcBitmap(); // this is some debug you can enable to visualize the dest bounding box //LineFloat(BoundingRect.left, BoundingRect.top, BoundingRect.right, BoundingRect.top, WHITE); //LineFloat(BoundingRect.right, BoundingRect.top, BoundingRect.right, BoundingRect.bottom, WHITE); //LineFloat(BoundingRect.right, BoundingRect.bottom, BoundingRect.left, BoundingRect.bottom, WHITE); //LineFloat(BoundingRect.left, BoundingRect.bottom, BoundingRect.left, BoundingRect.top, WHITE); } else // TODO: this can be even faster if we do not use an intermediat buffer { //Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height, destX, destY, imgBoundsPath); BuildOrgImgRectVxs(source.Width, source.Height, imgBoundsPath); // var destRectTransform = new AffineMat(); destRectTransform.Translate(destX, destY); //TODO: review reusable span generator an interpolator *** // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004] _reuseableAffine.SetElements(destRectTransform.CreateInvert()); _spanInterpolator.Transformer = _reuseableAffine; ImgSpanGen imgSpanGen = null; switch (source.BitDepth) { case 32: _img_NN_StepX.SetInterpolator(_spanInterpolator); _img_NN_StepX.SetSrcBitmap(source); imgSpanGen = _img_NN_StepX; break; //case 24: // imgSpanGen = new ImgSpanGenRGB_NNStepXby1(source, interpolator); // break; //case 8: // imgSpanGen = new ImgSpanGenGray_NNStepXby1(source, interpolator); // break; default: throw new NotImplementedException(); } TransformToVxs(ref destRectTransform, imgBoundsPath, v1); Render(v1, imgSpanGen); unchecked { _destImageChanged++; }; } } }
public void Clear(Color color) { RectInt clippingRectInt = GetClippingRect(); var destImage = this.DestImage; int width = destImage.Width; int height = destImage.Height; int[] buffer = destImage.GetBuffer32(); switch (destImage.BitDepth) { default: throw new NotSupportedException(); case 32: { //------------------------------ //fast clear buffer //skip clipping **** //TODO: reimplement clipping*** //------------------------------ if (color == Color.White) { //fast cleat with white color int n = buffer.Length; unsafe { fixed(void *head = &buffer[0]) { uint *head_i32 = (uint *)head; for (int i = n - 1; i >= 0; --i) { *head_i32 = 0xffffffff; //white (ARGB) head_i32++; } } } } else if (color == Color.Black) { //fast cleat with black color int n = buffer.Length; unsafe { fixed(void *head = &buffer[0]) { uint *head_i32 = (uint *)head; for (int i = n - 1; i >= 0; --i) { *head_i32 = 0xff000000; //black (ARGB) head_i32++; } } } } else { //other color //#if WIN // uint colorARGB = (uint)((color.alpha << 24) | ((color.red << 16) | (color.green << 8) | color.blue)); //#else // uint colorARGB = (uint)((color.alpha << 24) | ((color.blue << 16) | (color.green << 8) | color.red)); //#endif //ARGB uint colorARGB = (uint)((color.alpha << 24) | ((color.red << 16) | (color.green << 8) | color.blue)); int n = buffer.Length; unsafe { fixed(void *head = &buffer[0]) { uint *head_i32 = (uint *)head; for (int i = n - 1; i >= 0; --i) { *head_i32 = colorARGB; head_i32++; } } } } } break; } // switch (destImage.BitDepth) // { // case 8: // { // //int bytesBetweenPixels = destImage.BytesBetweenPixelsInclusive; // //byte byteColor = color.Red0To255; // //int clipRectLeft = clippingRectInt.Left; // //for (int y = clippingRectInt.Bottom; y < clippingRectInt.Top; ++y) // //{ // // int bufferOffset = destImage.GetBufferOffsetXY(clipRectLeft, y); // // for (int x = 0; x < clippingRectInt.Width; ++x) // // { // // buffer[bufferOffset] = color.blue; // // bufferOffset += bytesBetweenPixels; // // } // //} // throw new NotSupportedException("temp"); // } // case 24: // { // //int bytesBetweenPixels = destImage.BytesBetweenPixelsInclusive; // //int clipRectLeft = clippingRectInt.Left; // //for (int y = clippingRectInt.Bottom; y < clippingRectInt.Top; y++) // //{ // // int bufferOffset = destImage.GetBufferOffsetXY(clipRectLeft, y); // // for (int x = 0; x < clippingRectInt.Width; ++x) // // { // // buffer[bufferOffset + 0] = color.blue; // // buffer[bufferOffset + 1] = color.green; // // buffer[bufferOffset + 2] = color.red; // // bufferOffset += bytesBetweenPixels; // // } // //} // throw new NotSupportedException("temp"); // } // break; // case 32: // { // //------------------------------ // //fast clear buffer // //skip clipping **** // //TODO: reimplement clipping*** // //------------------------------ // if (color == Color.White) // { // //fast cleat with white color // int n = buffer.Length / 4; // unsafe // { // fixed (void* head = &buffer[0]) // { // uint* head_i32 = (uint*)head; // for (int i = n - 1; i >= 0; --i) // { // *head_i32 = 0xffffffff; //white (ARGB) // head_i32++; // } // } // } // } // else if (color == Color.Black) // { // //fast cleat with black color // int n = buffer.Length / 4; // unsafe // { // fixed (void* head = &buffer[0]) // { // uint* head_i32 = (uint*)head; // for (int i = n - 1; i >= 0; --i) // { // *head_i32 = 0xff000000; //black (ARGB) // head_i32++; // } // } // } // } // else // { // //other color //#if WIN // uint colorARGB = (uint)((color.alpha << 24) | ((color.red << 16) | (color.green << 8) | color.blue)); //#else // uint colorARGB = (uint)((color.alpha << 24) | ((color.blue << 16) | (color.green << 8) | color.red)); //#endif // int n = buffer.Length / 4; // unsafe // { // fixed (void* head = &buffer[0]) // { // uint* head_i32 = (uint*)head; // for (int i = n - 1; i >= 0; --i) // { // *head_i32 = colorARGB; // head_i32++; // } // } // } // } // } // break; // default: // throw new NotImplementedException(); // } }
public void SetClippingRect(RectInt rect) { ScanlineRasterizer.SetClipBox(rect); }