public void Render(IImageReaderWriter 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 = source.GetBounds();
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
Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height,
destX, destY, ox, oy, scaleX, scaleY, angleRadians, imgBoundsPath);
// We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004]
Affine sourceRectTransform = destRectTransform.CreateInvert();
var imgSpanGen = new ImgSpanGenRGBA_BilinearClip(
source,
Drawing.Color.Black,
new SpanInterpolatorLinear(sourceRectTransform));
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 intermediat buffer
{
Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height,
destX, destY, imgBoundsPath);
// We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004]
Affine sourceRectTransform = destRectTransform.CreateInvert();
var interpolator = new SpanInterpolatorLinear(sourceRectTransform);
ImgSpanGen imgSpanGen = null;
switch (source.BitDepth)
{
case 32:
imgSpanGen = new ImgSpanGenRGBA_NN_StepXBy1(source, interpolator);
break;
//case 24:
// imgSpanGen = new ImgSpanGenRGB_NNStepXby1(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);
}