C++程序  |  735行  |  20.86 KB

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* ---- includes ----------------------------------------------------------- */

#include "b_ImageEm/Functions.h"

/* ---- related objects  --------------------------------------------------- */

/* ---- typedefs ----------------------------------------------------------- */

/* ---- constants ---------------------------------------------------------- */

/* ------------------------------------------------------------------------- */

/* ========================================================================= */
/*                                                                           */
/* ---- \ghd{ external functions } ----------------------------------------- */
/*                                                                           */
/* ========================================================================= */

/* ------------------------------------------------------------------------- */

/** downscale by factor 2 (dstPtrA and srcPtrA may be identical) */
void bim_downscaleBy2( uint8*       dstPtrA, 
					   const uint8* srcPtrA,
					   uint32 srcWidthA,
					   uint32 effWidthA,
					   uint32 effHeightA )
{
	uint32 wsL = srcWidthA;
	uint32 w0L = effWidthA;
	uint32 h0L = effHeightA;
	uint32 w1L = w0L >> 1;
	uint32 h1L = h0L >> 1;

	const uint8* srcL = srcPtrA;
	uint8* dstL = dstPtrA;

	uint32 iL, jL;
	for( jL = 0; jL < h1L; jL++ )
	{
		for( iL = 0; iL < w1L; iL++ )
		{
			*dstL = ( ( uint32 )srcL[ 0 ] + srcL[ 1 ] + srcL[ wsL ] + srcL[ wsL + 1 ] + 2 ) >> 2;
			dstL++;
			srcL += 2;
		}
		srcL += ( wsL - w1L ) * 2;
	}
}

/* ------------------------------------------------------------------------- */

void bim_filterWarpInterpolation( struct bbs_Context* cpA,
								  uint8* dstImagePtrA, 
								  const uint8* srcImagePtrA,
								  uint32 srcImageWidthA,
								  uint32 srcImageHeightA,
							      const struct bts_Int16Vec2D* offsPtrA,
								  const struct bts_Flt16Alt2D* altPtrA,
								  uint32 dstWidthA,
								  uint32 dstHeightA,
								  struct bbs_UInt8Arr* bufPtrA,
								  uint32 scaleThresholdA )
{
	bbs_DEF_fNameL( "bim_filterWarpInterpolation" )

	uint32 w0L = srcImageWidthA;
	uint32 h0L = srcImageHeightA;

	const uint8* srcL = srcImagePtrA;
	uint8* dstL = dstImagePtrA;

	uint32 w1L = w0L;
	uint32 h1L = h0L;

	/* 16.16 */
	uint32 scaleThrL = scaleThresholdA;
	struct bts_Flt16Alt2D invAltL;

	/* matrix variables */
	int32 mxxL, mxyL, myxL, myyL, txL, tyL;

	flag downScaledL = FALSE;
	flag boundsOkL = TRUE;

	if( w0L == 0 || h0L == 0 || bts_Flt16Mat2D_det( &altPtrA->matE ) == 0 )
	{
		uint32 iL;
		for( iL = 0; iL < dstWidthA * dstHeightA; iL++ ) dstImagePtrA[ iL ] = 0;
		return;
	}

	/* compute inverse ALT */
	invAltL = bts_Flt16Alt2D_inverted( altPtrA );

	/* fixed point ALT 16.16 */
	if( invAltL.matE.bbpE <= 16 )
	{
		uint32 shlL = 16 - invAltL.matE.bbpE;
		mxxL = invAltL.matE.xxE << shlL;
		mxyL = invAltL.matE.xyE << shlL;
		myxL = invAltL.matE.yxE << shlL;
		myyL = invAltL.matE.yyE << shlL;
	}
	else
	{
		uint32 shrL = invAltL.matE.bbpE - 16;
		mxxL = ( ( invAltL.matE.xxE >> ( shrL - 1 ) ) + 1 ) >> 1;
		mxyL = ( ( invAltL.matE.xyE >> ( shrL - 1 ) ) + 1 ) >> 1;
		myxL = ( ( invAltL.matE.yxE >> ( shrL - 1 ) ) + 1 ) >> 1;
		myyL = ( ( invAltL.matE.yyE >> ( shrL - 1 ) ) + 1 ) >> 1;
	}

	if( invAltL.vecE.bbpE <= 16 )
	{
		uint32 shlL = 16 - invAltL.vecE.bbpE;
		txL = invAltL.vecE.xE << shlL;
		tyL = invAltL.vecE.yE << shlL;
	}
	else
	{
		uint32 shrL = invAltL.vecE.bbpE - 16;
		txL = ( ( invAltL.vecE.xE >> ( shrL - 1 ) ) + 1 ) >> 1;
		tyL = ( ( invAltL.vecE.yE >> ( shrL - 1 ) ) + 1 ) >> 1;
	}

	/* add offset */
	txL += ( int32 )offsPtrA->xE << 16;
	tyL += ( int32 )offsPtrA->yE << 16;

	if( scaleThresholdA > 0 )
	{
		/* compute downscale exponent */
		uint32 axxL = ( mxxL >= 0 ) ? mxxL : -mxxL;
		uint32 axyL = ( mxyL >= 0 ) ? mxyL : -mxyL;
		uint32 ayxL = ( myxL >= 0 ) ? myxL : -myxL;
		uint32 ayyL = ( myyL >= 0 ) ? myyL : -myyL;

		uint32 a1L = ( axxL > ayxL ) ? axxL : ayxL;
		uint32 a2L = ( axyL > ayyL ) ? axyL : ayyL;

		uint32 invScaleL = ( a1L < a2L ) ? a1L : a2L;
		uint32 scaleExpL = 0;
		while( ( invScaleL >> scaleExpL ) > scaleThrL ) scaleExpL++;
		while( ( scaleExpL > 0 ) && ( w0L >> scaleExpL ) < 2 ) scaleExpL--;
		while( ( scaleExpL > 0 ) && ( h0L >> scaleExpL ) < 2 ) scaleExpL--;

		/* downscale image */
		if( scaleExpL > 0 )
		{
			/* down sampling is limited to the effective area of the original image */

			/* compute effective area by mapping all corners of the dst rectangle */
			int32 xMinL = 0x7FFFFFFF;
			int32 yMinL = 0x7FFFFFFF;
			int32 xMaxL = 0x80000000;
			int32 yMaxL = 0x80000000;
			uint32 wEffL, hEffL;

			{
				int32 xL, yL;
				xL = txL;
				yL = tyL;
				xMinL = xL < xMinL ? xL : xMinL;
				yMinL = yL < yMinL ? yL : yMinL;
				xMaxL = xL > xMaxL ? xL : xMaxL;
				yMaxL = yL > yMaxL ? yL : yMaxL;
				xL = txL + mxxL * ( int32 )dstWidthA + mxyL * ( int32 )dstHeightA;
				yL = tyL + myxL * ( int32 )dstWidthA + myyL * ( int32 )dstHeightA;
				xMinL = xL < xMinL ? xL : xMinL;
				yMinL = yL < yMinL ? yL : yMinL;
				xMaxL = xL > xMaxL ? xL : xMaxL;
				yMaxL = yL > yMaxL ? yL : yMaxL;
				xL = txL + mxyL * ( int32 )dstHeightA;
				yL = tyL + myyL * ( int32 )dstHeightA;
				xMinL = xL < xMinL ? xL : xMinL;
				yMinL = yL < yMinL ? yL : yMinL;
				xMaxL = xL > xMaxL ? xL : xMaxL;
				yMaxL = yL > yMaxL ? yL : yMaxL;
				xL = txL + mxxL * ( int32 )dstWidthA;
				yL = tyL + myxL * ( int32 )dstWidthA;
				xMinL = xL < xMinL ? xL : xMinL;
				yMinL = yL < yMinL ? yL : yMinL;
				xMaxL = xL > xMaxL ? xL : xMaxL;
				yMaxL = yL > yMaxL ? yL : yMaxL;
			}

			xMaxL = ( xMaxL >> 16 ) + 2;
			yMaxL = ( yMaxL >> 16 ) + 2;
			xMinL >>= 16; 
			yMinL >>= 16; 

			/* ensre effective area stays within original frame */
			xMinL = 0 > xMinL ? 0 : xMinL;
			yMinL = 0 > yMinL ? 0 : yMinL;
			xMinL = ( int32 )w0L < xMinL ? w0L : xMinL;
			yMinL = ( int32 )h0L < yMinL ? h0L : yMinL;
			xMaxL = 0 > xMaxL ? 0 : xMaxL;
			yMaxL = 0 > yMaxL ? 0 : yMaxL;
			xMaxL = ( int32 )w0L < xMaxL ? w0L : xMaxL;
			yMaxL = ( int32 )h0L < yMaxL ? h0L : yMaxL;

			wEffL = xMaxL - xMinL;
			hEffL = yMaxL - yMinL;

			/* ensure downscaling does not reduce image to 0 */
			while( ( scaleExpL > 0 ) && ( wEffL >> scaleExpL ) < 2 ) scaleExpL--;
			while( ( scaleExpL > 0 ) && ( hEffL >> scaleExpL ) < 2 ) scaleExpL--;

			/* downscale */
			if( scaleExpL > 0 )
			{
				uint32 iL;
				w1L = wEffL >> 1;
				h1L = hEffL >> 1;
				if( bufPtrA == NULL ) bbs_ERROR1( "%s:\nPreallocated buffer is needed", fNameL );
				bbs_UInt8Arr_size( cpA, bufPtrA, w1L * h1L );
				bim_downscaleBy2( bufPtrA->arrPtrE, srcL + yMinL * w0L + xMinL, w0L, wEffL, hEffL );
				for( iL = 1; iL < scaleExpL; iL++ )
				{
					bim_downscaleBy2( bufPtrA->arrPtrE, bufPtrA->arrPtrE, w1L, w1L, h1L );
					w1L >>= 1;
					h1L >>= 1;
				}

				/* adjust inverted cordinates */
				txL -= ( xMinL << 16 );
				tyL -= ( yMinL << 16 );
				mxxL >>= scaleExpL;
				mxyL >>= scaleExpL;
				myxL >>= scaleExpL;
				myyL >>= scaleExpL;
				txL >>= scaleExpL;
				tyL >>= scaleExpL;
				srcL = bufPtrA->arrPtrE;
			}

			downScaledL = TRUE;
		}
	}
	
	/* if not downscaled and src and dst images are identcal then copy srcImage into buffer */
	if( !downScaledL && dstImagePtrA == srcImagePtrA ) 
	{
		uint32 iL;
		uint32 srcSizeL = srcImageWidthA * srcImageHeightA;
		if( bufPtrA == NULL ) bbs_ERROR1( "%s:\nPreallocated buffer is needed", fNameL );
		bbs_UInt8Arr_size( cpA, bufPtrA, srcSizeL );
		for( iL = 0; iL < srcSizeL; iL++ ) bufPtrA->arrPtrE[ iL ] = srcImagePtrA[ iL ];
		srcL = bufPtrA->arrPtrE;
	}

	/* compute destination image */

	/* bounds check (dst image fully inside src image? -> fast algorithm) */
	{
		int32 xL, yL;
		int32 wbL = w1L - 1;
		int32 hbL = h1L - 1;

		xL = txL >> 16;
		yL = tyL >> 16;
		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );

		xL = ( txL + mxxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
		yL = ( tyL + myxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
      
		xL = ( txL + mxyL * ( int32 )( dstHeightA - 1 ) ) >> 16;
		yL = ( tyL + myyL * ( int32 )( dstHeightA - 1 ) ) >> 16;
		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );

		xL = ( txL + mxyL * ( int32 )( dstHeightA - 1 ) + mxxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
		yL = ( tyL + myyL * ( int32 )( dstHeightA - 1 ) + myxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
	}

	if( boundsOkL )
	{
		int32 iL, jL;
		for( jL = 0; jL < ( int32 )dstHeightA; jL++ )
		{
			/* 16.16 */
			int32 xL = txL + mxyL * jL;
			int32 yL = tyL + myyL * jL;
			for( iL = 0; iL < ( int32 )dstWidthA; iL++ )
			{
				int32 x0L = xL >> 16;
				int32 y0L = yL >> 16;
				uint32 xf2L = xL & 0x0FFFF;
				uint32 yf2L = yL & 0x0FFFF;
				uint32 xf1L = 0x10000 - xf2L;
				uint32 yf1L = 0x10000 - yf2L;

				xL += mxxL;
				yL += myxL;

				{
					uint32 idxL = y0L * w1L + x0L;
					uint32 v1L = ( ( uint32 )srcL[ idxL       ] * xf1L + ( uint32 )srcL[ idxL + 1       ] * xf2L + 0x0800 ) >> 12;
					uint32 v2L = ( ( uint32 )srcL[ idxL + w1L ] * xf1L + ( uint32 )srcL[ idxL + w1L + 1 ] * xf2L + 0x0800 ) >> 12;
					*dstL++ = ( v1L * yf1L + v2L * yf2L + 0x080000 ) >> 20;
				}
			}
		}
	}
	else
	{
		int32 iL, jL;
		for( jL = 0; jL < ( int32 )dstHeightA; jL++ )
		{
			/* 16.16 */
			int32 xL = txL + mxyL * jL;
			int32 yL = tyL + myyL * jL;
			for( iL = 0; iL < ( int32 )dstWidthA; iL++ )
			{
				int32 x0L = xL >> 16;
				int32 y0L = yL >> 16;
				uint32 xf2L = xL & 0x0FFFF;
				uint32 yf2L = yL & 0x0FFFF;
				uint32 xf1L = 0x10000 - xf2L;
				uint32 yf1L = 0x10000 - yf2L;

				xL += mxxL;
				yL += myxL;

				if( y0L < 0 )
				{
					if( x0L < 0 )
					{
						*dstL++ = srcL[ 0 ];
					}
					else if( x0L >= ( int32 )w1L - 1 )
					{
						*dstL++ = srcL[ w1L - 1 ];
					}
					else
					{
						*dstL++ = ( ( uint32 )srcL[ x0L ] * xf1L + ( uint32 )srcL[ x0L + 1 ] * xf2L + 0x08000 ) >> 16;
					}
				}
				else if( y0L >= ( int32 )h1L - 1 )
				{
					if( x0L < 0 )
					{
						*dstL++ = srcL[ ( h1L - 1 ) * w1L ];
					}
					else if( x0L >= ( int32 )w1L - 1 )
					{
						*dstL++ = srcL[ ( h1L * w1L ) - 1 ];
					}
					else
					{
						uint32 idxL = ( h1L - 1 ) * w1L + x0L;
						*dstL++ = ( ( uint32 )srcL[ idxL ] * xf1L + ( uint32 )srcL[ idxL + 1 ] * xf2L + 0x08000 ) >> 16;
					}
				}
				else
				{
					if( x0L < 0 )
					{
						uint32 idxL = y0L * w1L;
						*dstL++ = ( ( uint32 )srcL[ idxL ] * yf1L + ( uint32 )srcL[ idxL + w1L ] * yf2L + 0x08000 ) >> 16;
					}
					else if( x0L >= ( int32 )w1L - 1 )
					{
						uint32 idxL = ( y0L + 1 ) * w1L - 1;
						*dstL++ = ( ( uint32 )srcL[ idxL ] * yf1L + ( uint32 )srcL[ idxL + w1L ] * yf2L + 0x08000 ) >> 16;
					}
					else
					{
						uint32 idxL = y0L * w1L + x0L;
						uint32 v1L = ( ( uint32 )srcL[ idxL       ] * xf1L + ( uint32 )srcL[ idxL + 1       ] * xf2L + 0x0800 ) >> 12;
						uint32 v2L = ( ( uint32 )srcL[ idxL + w1L ] * xf1L + ( uint32 )srcL[ idxL + w1L + 1 ] * xf2L + 0x0800 ) >> 12;
						*dstL++ = ( v1L * yf1L + v2L * yf2L + 0x080000 ) >> 20;
					}
				}
			}
		}
	}
}

/* ------------------------------------------------------------------------- */

void bim_filterWarpPixelReplication( struct bbs_Context* cpA,
								     uint8* dstImagePtrA, 
								     const uint8* srcImagePtrA,
								     uint32 srcImageWidthA,
								     uint32 srcImageHeightA,
								     const struct bts_Int16Vec2D* offsPtrA,
								     const struct bts_Flt16Alt2D* altPtrA,
								     uint32 dstWidthA,
								     uint32 dstHeightA,
								     struct bbs_UInt8Arr* bufPtrA,
								     uint32 scaleThresholdA )
{
	bbs_DEF_fNameL( "bim_filterWarpPixelReplication" )

	uint32 w0L = srcImageWidthA;
	uint32 h0L = srcImageHeightA;

	const uint8* srcL = srcImagePtrA;
	uint8* dstL = dstImagePtrA;

	uint32 w1L = w0L;
	uint32 h1L = h0L;

	/* 16.16 */
	uint32 scaleThrL = scaleThresholdA;
	struct bts_Flt16Alt2D invAltL;

	/* matrix variables */
	int32 mxxL, mxyL, myxL, myyL, txL, tyL;

	flag downScaledL = FALSE;
	flag boundsOkL = TRUE;

	if( w0L == 0 || h0L == 0 || bts_Flt16Mat2D_det( &altPtrA->matE ) == 0 )
	{
		uint32 iL;
		for( iL = 0; iL < dstWidthA * dstHeightA; iL++ ) dstImagePtrA[ iL ] = 0;
		return;
	}

	/* compute inverse ALT */
	invAltL = bts_Flt16Alt2D_inverted( altPtrA );

	/* fixed point ALT 16.16 */
	if( invAltL.matE.bbpE <= 16 )
	{
		uint32 shlL = 16 - invAltL.matE.bbpE;
		mxxL = invAltL.matE.xxE << shlL;
		mxyL = invAltL.matE.xyE << shlL;
		myxL = invAltL.matE.yxE << shlL;
		myyL = invAltL.matE.yyE << shlL;
	}
	else
	{
		uint32 shrL = invAltL.matE.bbpE - 16;
		mxxL = ( ( invAltL.matE.xxE >> ( shrL - 1 ) ) + 1 ) >> 1;
		mxyL = ( ( invAltL.matE.xyE >> ( shrL - 1 ) ) + 1 ) >> 1;
		myxL = ( ( invAltL.matE.yxE >> ( shrL - 1 ) ) + 1 ) >> 1;
		myyL = ( ( invAltL.matE.yyE >> ( shrL - 1 ) ) + 1 ) >> 1;
	}

	if( invAltL.vecE.bbpE <= 16 )
	{
		uint32 shlL = 16 - invAltL.vecE.bbpE;
		txL = invAltL.vecE.xE << shlL;
		tyL = invAltL.vecE.yE << shlL;
	}
	else
	{
		uint32 shrL = invAltL.vecE.bbpE - 16;
		txL = ( ( invAltL.vecE.xE >> ( shrL - 1 ) ) + 1 ) >> 1;
		tyL = ( ( invAltL.vecE.yE >> ( shrL - 1 ) ) + 1 ) >> 1;
	}

	/* add offset */
	txL += ( int32 )offsPtrA->xE << 16;
	tyL += ( int32 )offsPtrA->yE << 16;

	if( scaleThresholdA > 0 )
	{
		/* compute downscale exponent */
		uint32 axxL = ( mxxL >= 0 ) ? mxxL : -mxxL;
		uint32 axyL = ( mxyL >= 0 ) ? mxyL : -mxyL;
		uint32 ayxL = ( myxL >= 0 ) ? myxL : -myxL;
		uint32 ayyL = ( myyL >= 0 ) ? myyL : -myyL;

		uint32 a1L = ( axxL > ayxL ) ? axxL : ayxL;
		uint32 a2L = ( axyL > ayyL ) ? axyL : ayyL;

		uint32 invScaleL = ( a1L < a2L ) ? a1L : a2L;
		uint32 scaleExpL = 0;
		while( ( invScaleL >> scaleExpL ) > scaleThrL ) scaleExpL++;
		while( ( scaleExpL > 0 ) && ( w0L >> scaleExpL ) < 2 ) scaleExpL--;
		while( ( scaleExpL > 0 ) && ( h0L >> scaleExpL ) < 2 ) scaleExpL--;

		/* downscale image */
		if( scaleExpL > 0 )
		{
			/* down sampling is limited to the effective area of the original image */

			/* compute effective area by mapping all corners of the dst rectangle */
			int32 xMinL = 0x7FFFFFFF;
			int32 yMinL = 0x7FFFFFFF;
			int32 xMaxL = 0x80000000;
			int32 yMaxL = 0x80000000;
			uint32 wEffL, hEffL;

			{
				int32 xL, yL;
				xL = txL;
				yL = tyL;
				xMinL = xL < xMinL ? xL : xMinL;
				yMinL = yL < yMinL ? yL : yMinL;
				xMaxL = xL > xMaxL ? xL : xMaxL;
				yMaxL = yL > yMaxL ? yL : yMaxL;
				xL = txL + mxxL * ( int32 )dstWidthA + mxyL * ( int32 )dstHeightA;
				yL = tyL + myxL * ( int32 )dstWidthA + myyL * ( int32 )dstHeightA;
				xMinL = xL < xMinL ? xL : xMinL;
				yMinL = yL < yMinL ? yL : yMinL;
				xMaxL = xL > xMaxL ? xL : xMaxL;
				yMaxL = yL > yMaxL ? yL : yMaxL;
				xL = txL + mxyL * ( int32 )dstHeightA;
				yL = tyL + myyL * ( int32 )dstHeightA;
				xMinL = xL < xMinL ? xL : xMinL;
				yMinL = yL < yMinL ? yL : yMinL;
				xMaxL = xL > xMaxL ? xL : xMaxL;
				yMaxL = yL > yMaxL ? yL : yMaxL;
				xL = txL + mxxL * ( int32 )dstWidthA;
				yL = tyL + myxL * ( int32 )dstWidthA;
				xMinL = xL < xMinL ? xL : xMinL;
				yMinL = yL < yMinL ? yL : yMinL;
				xMaxL = xL > xMaxL ? xL : xMaxL;
				yMaxL = yL > yMaxL ? yL : yMaxL;
			}

			xMaxL = ( xMaxL >> 16 ) + 2;
			yMaxL = ( yMaxL >> 16 ) + 2;
			xMinL >>= 16; 
			yMinL >>= 16; 

			/* ensre effective area stays within original frame */
			xMinL = 0 > xMinL ? 0 : xMinL;
			yMinL = 0 > yMinL ? 0 : yMinL;
			xMinL = ( int32 )w0L < xMinL ? w0L : xMinL;
			yMinL = ( int32 )h0L < yMinL ? h0L : yMinL;
			xMaxL = 0 > xMaxL ? 0 : xMaxL;
			yMaxL = 0 > yMaxL ? 0 : yMaxL;
			xMaxL = ( int32 )w0L < xMaxL ? w0L : xMaxL;
			yMaxL = ( int32 )h0L < yMaxL ? h0L : yMaxL;

			wEffL = xMaxL - xMinL;
			hEffL = yMaxL - yMinL;

			/* ensure downscaling does not reduce image to 0 */
			while( ( scaleExpL > 0 ) && ( wEffL >> scaleExpL ) < 2 ) scaleExpL--;
			while( ( scaleExpL > 0 ) && ( hEffL >> scaleExpL ) < 2 ) scaleExpL--;

			/* downscale */
			if( scaleExpL > 0 )
			{
				uint32 iL;
				w1L = wEffL >> 1;
				h1L = hEffL >> 1;
				if( bufPtrA == NULL ) bbs_ERROR1( "%s:\nPreallocated buffer is needed", fNameL );
				bbs_UInt8Arr_size( cpA, bufPtrA, w1L * h1L );
				bim_downscaleBy2( bufPtrA->arrPtrE, srcL + yMinL * w0L + xMinL, w0L, wEffL, hEffL );
				for( iL = 1; iL < scaleExpL; iL++ )
				{
					bim_downscaleBy2( bufPtrA->arrPtrE, bufPtrA->arrPtrE, w1L, w1L, h1L );
					w1L >>= 1;
					h1L >>= 1;
				}

				/* adjust inverted cordinates */
				txL -= ( xMinL << 16 );
				tyL -= ( yMinL << 16 );
				mxxL >>= scaleExpL;
				mxyL >>= scaleExpL;
				myxL >>= scaleExpL;
				myyL >>= scaleExpL;
				txL >>= scaleExpL;
				tyL >>= scaleExpL;
				srcL = bufPtrA->arrPtrE;
			}

			downScaledL = TRUE;
		}
	}
	
	/* if not downscaled and src and dst images are identcal then copy srcImage into buffer */
	if( !downScaledL && dstImagePtrA == srcImagePtrA ) 
	{
		uint32 iL;
		uint32 srcSizeL = srcImageWidthA * srcImageHeightA;
		if( bufPtrA == NULL ) bbs_ERROR1( "%s:\nPreallocated buffer is needed", fNameL );
		bbs_UInt8Arr_size( cpA, bufPtrA, srcSizeL );
		for( iL = 0; iL < srcSizeL; iL++ ) bufPtrA->arrPtrE[ iL ] = srcImagePtrA[ iL ];
		srcL = bufPtrA->arrPtrE;
	}

	/* compute destination image */

	/* bounds check (dst image fully inside src image? -> fast algorithm) */
	{
		int32 xL, yL;
		int32 wbL = w1L - 1;
		int32 hbL = h1L - 1;

		xL = txL >> 16;
		yL = tyL >> 16;
		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );

		xL = ( txL + mxxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
		yL = ( tyL + myxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
      
		xL = ( txL + mxyL * ( int32 )( dstHeightA - 1 ) ) >> 16;
		yL = ( tyL + myyL * ( int32 )( dstHeightA - 1 ) ) >> 16;
		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );

		xL = ( txL + mxyL * ( int32 )( dstHeightA - 1 ) + mxxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
		yL = ( tyL + myyL * ( int32 )( dstHeightA - 1 ) + myxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
	}

	if( boundsOkL )
	{
		int32 iL, jL;
		for( jL = 0; jL < ( int32 )dstHeightA; jL++ )
		{
			/* 16.16 */
			int32 xL = txL + mxyL * jL;
			int32 yL = tyL + myyL * jL;
			for( iL = 0; iL < ( int32 )dstWidthA; iL++ )
			{
				/* nearest whole position */
				*dstL++ = srcL[ ( ( ( yL >> 15 ) + 1 ) >> 1 ) * w1L + ( ( ( xL >> 15 ) + 1 ) >> 1 ) ];
				xL += mxxL;
				yL += myxL;
			}
		}
	}
	else
	{
		int32 iL, jL;
		for( jL = 0; jL < ( int32 )dstHeightA; jL++ )
		{
			/* 16.16 */
			int32 xL = txL + mxyL * jL;
			int32 yL = tyL + myyL * jL;
			for( iL = 0; iL < ( int32 )dstWidthA; iL++ )
			{
				/* nearest whole position */
				int32 x0L = ( ( xL >> 15 ) + 1 ) >> 1;
				int32 y0L = ( ( yL >> 15 ) + 1 ) >> 1;
				xL += mxxL;
				yL += myxL;

				if( y0L < 0 )
				{
					if( x0L < 0 )
					{
						*dstL++ = srcL[ 0 ];
					}
					else if( x0L >= ( int32 )w1L - 1 )
					{
						*dstL++ = srcL[ w1L - 1 ];
					}
					else
					{
						*dstL++ = srcL[ x0L ];
					}
				}
				else if( y0L >= ( int32 )h1L - 1 )
				{
					if( x0L < 0 )
					{
						*dstL++ = srcL[ ( h1L - 1 ) * w1L ];
					}
					else if( x0L >= ( int32 )w1L - 1 )
					{
						*dstL++ = srcL[ ( h1L * w1L ) - 1 ];
					}
					else
					{
						*dstL++ = srcL[ ( h1L - 1 ) * w1L + x0L ];
					}
				}
				else
				{
					if( x0L < 0 )
					{
						*dstL++ = srcL[ y0L * w1L ];
					}
					else if( x0L >= ( int32 )w1L - 1 )
					{
						*dstL++ = srcL[ ( y0L + 1 ) * w1L - 1 ];
					}
					else
					{
						*dstL++ = srcL[ y0L * w1L + x0L ];
					}
				}
			}
		}
	}
}

/* ------------------------------------------------------------------------- */

void bim_filterWarp( struct bbs_Context* cpA,
					 uint8* dstImagePtrA, 
					 const uint8* srcImagePtrA,
					 uint32 srcImageWidthA,
					 uint32 srcImageHeightA,
				     const struct bts_Int16Vec2D* offsPtrA,
					 const struct bts_Flt16Alt2D* altPtrA,
					 uint32 dstWidthA,
					 uint32 dstHeightA,
					 struct bbs_UInt8Arr* bufPtrA,
					 uint32 scaleThresholdA,
					 flag interpolateA )
{
	if( interpolateA )
	{
		bim_filterWarpInterpolation( cpA, dstImagePtrA, srcImagePtrA, srcImageWidthA, srcImageHeightA, offsPtrA, altPtrA, dstWidthA, dstHeightA, bufPtrA, scaleThresholdA );
	}
	else
	{
		bim_filterWarpPixelReplication( cpA, dstImagePtrA, srcImagePtrA, srcImageWidthA, srcImageHeightA, offsPtrA, altPtrA, dstWidthA, dstHeightA, bufPtrA, scaleThresholdA );
	}
}

/* ------------------------------------------------------------------------- */