public static AffineMat GetRotateMat(double rad, double center_x, double center_y) { AffineMat mat = s_Iden;//copy mat.Rotate(rad, center_x, center_y); return(mat); }
//----------------------------------------- //helpers public static AffineMat GetRotateMat(double rad) { AffineMat mat = s_Iden;//copy mat.Rotate(rad); return(mat); }
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 Q1Rect sourceBounds = source.GetBounds(); Q1Rect destBounds = _destBitmapBlender.GetBounds(); sourceBounds.Offset((int)destX, (int)destY); if (!Q1Rect.DoIntersect(sourceBounds, destBounds)) { if (inScaleX != 1 || inScaleY != 1 || angleRadians != 0) { throw new NotImplementedException(); } return; } } double scaleX = inScaleX; double scaleY = inScaleY; ICoordTransformer 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. AffineMat destRectTransform = AffineMat.Iden(); destRectTransform.Translate(-_ox, -_oy); destRectTransform.Scale(scaleX, scaleY); destRectTransform.Rotate(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] _reuseableAffine.SetElements(destRectTransform.CreateInvert()); _spanInterpolator.Transformer = _reuseableAffine; _currentImgSpanGen.BackgroundColor = Drawing.Color.Black; _currentImgSpanGen.SetInterpolator(_spanInterpolator); _currentImgSpanGen.SetSrcBitmap(source); destRectTransform.TransformToVxs(imgBoundsPath, v1); //not inverted version Render(v1, _currentImgSpanGen); _currentImgSpanGen.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: if (_imgSpanGenCustom != null) { //use custom span gen _imgSpanGenCustom.SetInterpolator(_spanInterpolator); _imgSpanGenCustom.SetSrcBitmap(source); imgSpanGen = _imgSpanGenCustom; } else { _imgSpanGenNNStepXBy1.SetInterpolator(_spanInterpolator); _imgSpanGenNNStepXBy1.SetSrcBitmap(source); imgSpanGen = _imgSpanGenNNStepXBy1; } break; //case 24: // imgSpanGen = new ImgSpanGenRGB_NNStepXby1(source, interpolator); // break; //case 8: // imgSpanGen = new ImgSpanGenGray_NNStepXby1(source, interpolator); // break; default: throw new NotImplementedException(); } TransformToVxs(destRectTransform, imgBoundsPath, v1); Render(v1, imgSpanGen); unchecked { _destImageChanged++; }; } } }