C++程序  |  808行  |  26.62 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_BasicEm/Functions.h"
#include "b_BasicEm/Math.h"
#include "b_BitFeatureEm/LocalScanner.h"

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

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

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

/** allocates arays */
void bbf_LocalScanner_alloc( struct bbs_Context* cpA,
							 struct bbf_LocalScanner* ptrA, 
							 struct bbs_MemTbl* mtpA )
{
	struct bbs_MemTbl memTblL = *mtpA;
	struct bbs_MemSeg* espL = bbs_MemTbl_segPtr( cpA, &memTblL, 0 );
	struct bbs_MemSeg* sspL = bbs_MemTbl_sharedSegPtr( cpA, &memTblL, 0 );

	/* filter patch dimension */
	uint32 proL = ptrA->maxRadiusE;
	uint32 pwoL = ( proL << 1 ) + 1;

	/* output image size (bit image) */
	uint32 woL = ptrA->maxImageWidthE;
	uint32 hoL = ptrA->maxImageHeightE;

	if( ptrA->minScaleExpE > 0 )
	{
		/* allocate working image */
		bbs_UInt8Arr_create( cpA, &ptrA->workImageBufferE, ( woL >> 1 ) * ( hoL >> 1 ), espL );
		bbs_UInt8Arr_fill( cpA, &ptrA->workImageBufferE, 0 );
	}

	/* allocate bit image */
	bim_UInt32Image_create( cpA, &ptrA->bitImageE, woL, ( hoL >> 5 ) + ( ( ( hoL & 0x1F ) != 0 ) ? 1 : 0 ), espL );
	bim_UInt32Image_setAllPixels( cpA, &ptrA->bitImageE, 0, 0 );

	/* allocate patch buffer */
	bbs_UInt32Arr_create( cpA, &ptrA->patchBufferE, ptrA->bitImageE.widthE, espL );
	bbs_UInt32Arr_fill( cpA, &ptrA->patchBufferE, 0 );

	/* allocate table */
	bim_UInt32Image_create( cpA, &ptrA->satE, woL + pwoL, pwoL + 1, sspL );
}

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

/** downscales original image by factor 2 */
void bbf_LocalScanner_downscale0( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
{
	int32 w0L = ptrA->origWidthE;
	int32 h0L = ptrA->origHeightE;

	int32 w1L = ( w0L - ptrA->xOffE ) >> 1;
	int32 h1L = ( h0L - ptrA->yOffE ) >> 1;

	const uint8* iArrL = ptrA->origImagePtrE + ptrA->xOffE + ptrA->yOffE * w0L;
		  uint8* oArrL = ptrA->workImageBufferE.arrPtrE;

	int32 iL, jL;
	int32 kL = 0;

	bbs_UInt8Arr_size( cpA, &ptrA->workImageBufferE, w1L * h1L );
	ptrA->workImagePtrE = ptrA->workImageBufferE.arrPtrE;
	ptrA->workWidthE = w1L;
	ptrA->workHeightE = h1L;

	for( jL = 0; jL < h1L; jL++ )
	{
		for( iL = 0; iL < w1L; iL++ )
		{
			int32 idxL = jL * 2 * w0L + iL * 2;
			oArrL[ kL++ ] = ( ( uint32 )iArrL[ idxL           ] + 
										iArrL[ idxL + 1       ] + 
										iArrL[ idxL + w0L     ] + 
										iArrL[ idxL + w0L + 1 ] + 2 ) >> 2;
		}
	}
}

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

/** downscales work image by factor 2 */
void bbf_LocalScanner_downscale1( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
{
	int32 w0L = ptrA->workWidthE;
	int32 h0L = ptrA->workHeightE;
	int32 w1L = w0L >> 1;
	int32 h1L = h0L >> 1;

    uint8* arrL = ptrA->workImageBufferE.arrPtrE;

	int32 iL, jL;
	int32 kL = 0;

	for( jL = 0; jL < h1L; jL++ )
	{
		for( iL = 0; iL < w1L; iL++ )
		{
			int32 idxL = jL * 2 * w0L + iL * 2;
			arrL[ kL++ ] = ( ( uint32 )arrL[ idxL ] + 
									   arrL[ idxL + 1 ] + 
									   arrL[ idxL + w0L ] + 
									   arrL[ idxL + w0L + 1 ] + 2 ) >> 2;
		}
	}

	ptrA->workWidthE = w1L;
	ptrA->workHeightE = h1L;
}

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

/** downscales by factor 2 */
void bbf_LocalScanner_downscale( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
{
	uint32 iL;
	if( ptrA->scaleExpE > 0 ) bbf_LocalScanner_downscale0( cpA, ptrA );
	for( iL = 1; iL < ptrA->scaleExpE; iL++ ) bbf_LocalScanner_downscale1( cpA, ptrA );
}

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

/** computes bit image */
void bbf_LocalScanner_createBitImage( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
{
	bbs_DEF_fNameL( "void bbf_LocalScanner_createBitImage( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )" )

	uint32 iL, jL;

	uint32 proL = ptrA->bitParamE.outerRadiusE;
	uint32 priL = ptrA->bitParamE.innerRadiusE;
	uint32 pwoL = ( proL << 1 ) + 1;
	uint32 pwiL = ( priL << 1 ) + 1;

	/* areas of inner and outer rectangles */
	uint32 poAreaL = pwoL * pwoL;
	uint32 piAreaL = pwiL * pwiL;

	uint32 wL, hL; /* input image size */

	uint32 wsL, hsL; 
	uint32* satL;
	uint32 satSizeL;
	uint32 swi1L = 0; /* writing index */
	uint32 swi2L = 0; /* writing index */
	uint32 sriL = 0;  /* reading index */
	uint32 siL[ 8 ];

	uint32  bitMaskL;
	uint32* bitRowL;


	if( proL <= priL ) 
	{
		bbs_ERROR1( "%s:\n outer radius <= inner radius", fNameL );
		return;
	}

	/* input image size */
	wL = ptrA->workWidthE;
	hL = ptrA->workHeightE;

	if( wL <= pwoL || hL <= pwoL ) 
	{
		bbs_ERROR1( "%s:\n image is too small", fNameL );
		return;
	}

	ptrA->currentWidthE  = wL;
	ptrA->currentHeightE = hL;

	/* reset scan region */
	ptrA->workScanRegionE = bts_Int16Rect_create( 0, 0, ptrA->currentWidthE, ptrA->currentHeightE );

	/* initialize bit image */
	bim_UInt32Image_size( cpA, &ptrA->bitImageE, wL, ( hL >> 5 ) + ( ( ( hL & 0x1F ) != 0 ) ? 1 : 0 ) );
	bim_UInt32Image_setAllPixels( cpA, &ptrA->bitImageE, 0, 0 );

	bitMaskL = 1;
	bitRowL = ( uint32* )ptrA->bitImageE.arrE.arrPtrE;

	/* width of table */
	wsL = wL + pwoL;

	/* height of table */
	hsL = pwoL + 1;

	bim_UInt32Image_size( cpA, &ptrA->satE, wsL, hsL );

	satL = ( uint32* )ptrA->satE.arrE.arrPtrE;
	satSizeL = ptrA->satE.arrE.sizeE;

	/* compute table and bit image */
	for( iL = wsL * ( proL + 1 ); iL > 0; iL-- ) satL[ swi1L++ ] = 0;
	swi2L = swi1L - wsL;

	for( jL = 0; jL < hL + proL; jL++ )
	{
		if( jL < hL ) /* rescale area */
		{
			const uint8* arr0L = &ptrA->workImagePtrE[ jL * wL ];
			uint32 hSumL = 0;
			for( iL = 0; iL <= proL; iL++ ) satL[ swi1L++ ] = 0;
			swi2L += iL;
			for( iL = 0; iL < wL; iL++ )   satL[ swi1L++ ] = ( hSumL += arr0L[ iL ] ) + satL[ swi2L++ ];
			for( iL = 0; iL < proL; iL++ ) satL[ swi1L++ ] =   hSumL                  + satL[ swi2L++ ];
		}
		else /* image is processed - fill in 0s */
		{
			for( iL = 0; iL < wsL; iL++ ) satL[ swi1L++ ] = satL[ swi2L++ ];
		}

		swi1L = ( swi1L < satSizeL ) ? swi1L : 0;
		swi2L = ( swi2L < satSizeL ) ? swi2L : 0;

		/* fill line in bit image */
		if( jL >= proL ) 
		{
			const uint32* rSatL = satL;

			/* table coordinate indices for outer rectangle */
			siL[ 0 ] = sriL;
			siL[ 1 ] = siL[ 0 ] + pwoL;
			siL[ 2 ] = siL[ 0 ] + pwoL * wsL;
			siL[ 2 ] -= ( siL[ 2 ] >= satSizeL ) ? satSizeL : 0;
			siL[ 3 ] = siL[ 2 ] + pwoL;

			/* table coordinate indices for inner rectangle */
			siL[ 4 ] = siL[ 0 ] + ( proL - priL ) * wsL + ( proL - priL );
			siL[ 4 ] -= ( siL[ 4 ] >= satSizeL ) ? satSizeL : 0;
			siL[ 5 ] = siL[ 4 ] + pwiL;
			siL[ 6 ] = siL[ 4 ] + pwiL * wsL;
			siL[ 6 ] -= ( siL[ 6 ] >= satSizeL ) ? satSizeL : 0;
			siL[ 7 ] = siL[ 6 ] + pwiL;
			sriL += wsL;
			if( sriL == satSizeL ) sriL = 0;

			for( iL = 0; iL < wL; iL++ )
			{
				uint32 oAvgL = ( rSatL[ siL[ 0 ] ] - rSatL[ siL[ 1 ] ] - rSatL[ siL[ 2 ] ] + rSatL[ siL[ 3 ] ] ) * piAreaL;
				uint32 iAvgL = ( rSatL[ siL[ 4 ] ] - rSatL[ siL[ 5 ] ] - rSatL[ siL[ 6 ] ] + rSatL[ siL[ 7 ] ] ) * poAreaL;
				bitRowL[ iL ] |= ( iAvgL > oAvgL ) ? bitMaskL : 0;
				rSatL++;
			}
			if( ( bitMaskL <<= 1 ) == 0 )
			{
				bitRowL += wL;
				bitMaskL = 1;
			}
		}
	}
}

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

/** inilialize patch buffer */
void bbf_LocalScanner_initPatchBuffer( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
{
	int32 ybL = ptrA->workScanRegionE.y1E >> 5;
	int32 yoL = ptrA->workScanRegionE.y1E & 0x1F;
	int32 xbL = ptrA->workScanRegionE.x1E;
	uint32 wsrWidthL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E;

	bbs_UInt32Arr_size( cpA, &ptrA->patchBufferE, ptrA->bitImageE.widthE );

	if( yoL == 0 )
	{
		bbs_memcpy32( ptrA->patchBufferE.arrPtrE + xbL, 
			          ptrA->bitImageE.arrE.arrPtrE + ybL * ptrA->bitImageE.widthE + xbL, 
					  wsrWidthL );
	}
	else if( ybL == ( int32 )ptrA->bitImageE.heightE - 1 )
	{
		uint32* dstL = ptrA->patchBufferE.arrPtrE + xbL;
		const uint32* srcL = ptrA->bitImageE.arrE.arrPtrE + ybL * ptrA->bitImageE.widthE + xbL;
		uint32 iL;
		for( iL = 0; iL < wsrWidthL; iL++ ) dstL[ iL ] = srcL[ iL ] >> yoL;
	}
	else
	{
		uint32* dstL = ptrA->patchBufferE.arrPtrE + xbL;
		const uint32* src0L = ptrA->bitImageE.arrE.arrPtrE + ybL * ptrA->bitImageE.widthE + xbL;
		const uint32* src1L = src0L + ptrA->bitImageE.widthE;
		uint32 iL;
		uint32 slL = 32 - yoL;
		for( iL = 0; iL < wsrWidthL; iL++ ) dstL[ iL ] = ( src0L[ iL ] >> yoL ) | ( src1L[ iL ] << slL );
	}
}

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

/* sets work scan region from original scan region according to scale exponent */
void bbf_LocalScanner_setWorkScanRegion( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
{
	int32 xMinL = ptrA->origScanRegionE.x1E >> ptrA->scaleExpE;
	int32 yMinL = ptrA->origScanRegionE.y1E >> ptrA->scaleExpE;
	int32 xMaxL = ptrA->origScanRegionE.x2E >> ptrA->scaleExpE;
	int32 yMaxL = ptrA->origScanRegionE.y2E >> ptrA->scaleExpE;
	ptrA->workScanRegionE.x1E = ( xMinL < 0 ) ? 0 : xMinL;
	ptrA->workScanRegionE.y1E = ( yMinL < 0 ) ? 0 : yMinL;
	ptrA->workScanRegionE.x2E = ( xMaxL > ( int32 )ptrA->currentWidthE ) ? ptrA->currentWidthE : xMaxL;
	ptrA->workScanRegionE.y2E = ( yMaxL > ( int32 )ptrA->currentHeightE ) ? ptrA->currentHeightE : yMaxL;
}

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

/* ========================================================================= */
/*                                                                           */
/* ---- \ghd{ constructor / destructor } ----------------------------------- */
/*                                                                           */
/* ========================================================================= */

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

void bbf_LocalScanner_init( struct bbs_Context* cpA,
					        struct bbf_LocalScanner* ptrA )
{
	ptrA->xE = 0;
	ptrA->yE = 0;
	ptrA->xOffE = 0;
	ptrA->yOffE = 0;
	ptrA->currentWidthE = 0;
	ptrA->currentHeightE = 0;
	ptrA->workWidthE = 0;
	ptrA->workHeightE = 0;
	ptrA->workImagePtrE = NULL;
	ptrA->origWidthE = 0;
	ptrA->origHeightE = 0;
	ptrA->origImagePtrE = NULL;
	bbf_BitParam_init( cpA, &ptrA->bitParamE );
	bbs_UInt8Arr_init( cpA, &ptrA->workImageBufferE );
	bim_UInt32Image_init( cpA, &ptrA->satE );
	bim_UInt32Image_init( cpA, &ptrA->bitImageE );
	bbs_UInt32Arr_init( cpA, &ptrA->patchBufferE );
	bts_Int16Rect_init( cpA, &ptrA->origScanRegionE );
	bts_Int16Rect_init( cpA, &ptrA->workScanRegionE );

	ptrA->patchWidthE = 0;
	ptrA->patchHeightE = 0;
	ptrA->scaleExpE = 0;
	ptrA->maxImageWidthE = 0;
	ptrA->maxImageHeightE = 0;
	ptrA->minScaleExpE = 0;
	ptrA->maxRadiusE = 0;
}

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

void bbf_LocalScanner_exit( struct bbs_Context* cpA,
				            struct bbf_LocalScanner* ptrA )
{
	ptrA->xE = 0;
	ptrA->yE = 0;
	ptrA->xOffE = 0;
	ptrA->yOffE = 0;
	ptrA->currentWidthE = 0;
	ptrA->currentHeightE = 0;
	ptrA->workWidthE = 0;
	ptrA->workHeightE = 0;
	ptrA->workImagePtrE = NULL;
	ptrA->origWidthE = 0;
	ptrA->origHeightE = 0;
	ptrA->origImagePtrE = NULL;
	bbf_BitParam_exit( cpA, &ptrA->bitParamE );
	bbs_UInt8Arr_exit( cpA, &ptrA->workImageBufferE );
	bim_UInt32Image_exit( cpA, &ptrA->satE );
	bim_UInt32Image_exit( cpA, &ptrA->bitImageE );
	bbs_UInt32Arr_exit( cpA, &ptrA->patchBufferE );
	bts_Int16Rect_exit( cpA, &ptrA->origScanRegionE );
	bts_Int16Rect_exit( cpA, &ptrA->workScanRegionE );

	ptrA->patchWidthE = 0;
	ptrA->patchHeightE = 0;
	ptrA->scaleExpE = 0;
	ptrA->maxImageWidthE = 0;
	ptrA->maxImageHeightE = 0;
	ptrA->minScaleExpE = 0;
	ptrA->maxRadiusE = 0;
}

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

/* ========================================================================= */
/*                                                                           */
/* ---- \ghd{ operators } -------------------------------------------------- */
/*                                                                           */
/* ========================================================================= */

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

void bbf_LocalScanner_copy( struct bbs_Context* cpA,
				            struct bbf_LocalScanner* ptrA, 
					        const struct bbf_LocalScanner* srcPtrA )
{
	bbs_ERROR0( "bbf_LocalScanner_copy:\n Function is not available" );
}

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

flag bbf_LocalScanner_equal( struct bbs_Context* cpA,
							 const struct bbf_LocalScanner* ptrA, 
							 const struct bbf_LocalScanner* srcPtrA )
{
	bbs_ERROR0( "bbf_LocalScanner_equal:\n Function is not available" );
	return FALSE;
}

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

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

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

uint32 bbf_LocalScanner_positions( const struct bbf_LocalScanner* ptrA )
{ 
	int32 wL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E - ptrA->patchWidthE;
	int32 hL = ptrA->workScanRegionE.y2E - ptrA->workScanRegionE.y1E - ptrA->patchHeightE;
	return ( ( wL < 0 ) ? 0 : wL ) * ( ( hL < 0 ) ? 0 : hL );
}

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

uint32 bbf_LocalScanner_scanIndex( const struct bbf_LocalScanner* ptrA )
{
	int32 wL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E - ptrA->patchWidthE;
	return ( ptrA->yE - ptrA->workScanRegionE.y1E ) * wL + ( ptrA->xE - ptrA->workScanRegionE.x1E );
}

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

void bbf_LocalScanner_pos( const struct bbf_LocalScanner* ptrA, int32* xPtrA, int32* yPtrA )
{
	*xPtrA = ( ( ptrA->xE << ptrA->scaleExpE ) + ptrA->xOffE ) << 16;
	*yPtrA = ( ( ptrA->yE << ptrA->scaleExpE ) + ptrA->yOffE ) << 16;
}

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

void bbf_LocalScanner_idxPos( const struct bbf_LocalScanner* ptrA, uint32 scanIndexA, int32* xPtrA, int32* yPtrA )
{
	uint32 wL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E - ptrA->patchWidthE;
	int32 xL = ( scanIndexA % wL ) + ptrA->workScanRegionE.x1E;
	int32 yL = ( scanIndexA / wL ) + ptrA->workScanRegionE.y1E;
	*xPtrA = ( ( xL << ptrA->scaleExpE ) + ptrA->xOffE ) << 16;
	*yPtrA = ( ( yL << ptrA->scaleExpE ) + ptrA->yOffE ) << 16;
}

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

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

/* ------------------------------------------------------------------------- */
	
void bbf_LocalScanner_create( struct bbs_Context* cpA,
							  struct bbf_LocalScanner* ptrA, 
							  uint32 patchWidthA,
							  uint32 patchHeightA,
							  uint32 scaleExpA,
							  uint32 maxImageWidthA,
							  uint32 maxImageHeightA,
							  uint32 minScaleExpA,
							  uint32 maxRadiusA,
							  struct bbs_MemTbl* mtpA )
{
	ptrA->patchWidthE = patchWidthA;
	ptrA->patchHeightE = patchHeightA;
	ptrA->scaleExpE = scaleExpA;
	ptrA->maxImageWidthE = maxImageWidthA;
	ptrA->maxImageHeightE = maxImageHeightA;
	ptrA->minScaleExpE = minScaleExpA;
	ptrA->maxRadiusE = maxRadiusA;
	bbf_LocalScanner_alloc( cpA, ptrA, mtpA );
}

/* ------------------------------------------------------------------------- */
	
void bbf_LocalScanner_bitParam( struct bbs_Context* cpA,
							    struct bbf_LocalScanner* ptrA,
								const struct bbf_BitParam* bitParamPtrA )
{
	if( !bbf_BitParam_equal( cpA, &ptrA->bitParamE, bitParamPtrA ) )
	{
		bbf_BitParam_copy( cpA, &ptrA->bitParamE, bitParamPtrA );
		bbf_LocalScanner_createBitImage( cpA, ptrA );
	}

	bbf_LocalScanner_resetScan( cpA, ptrA );
}

/* ------------------------------------------------------------------------- */
	
void bbf_LocalScanner_origScanRegion( struct bbs_Context* cpA,
									  struct bbf_LocalScanner* ptrA,
									  const struct bts_Int16Rect* scanRegionPtrA )
{
	ptrA->origScanRegionE = *scanRegionPtrA;
	bbf_LocalScanner_setWorkScanRegion( cpA, ptrA );
	bbf_LocalScanner_resetScan( cpA, ptrA );
}

/* ------------------------------------------------------------------------- */
	
/* ========================================================================= */
/*                                                                           */
/* ---- \ghd{ I/O } -------------------------------------------------------- */
/*                                                                           */
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
	
uint32 bbf_LocalScanner_memSize( struct bbs_Context* cpA,
								 const struct bbf_LocalScanner* ptrA )
{
	uint32 memSizeL = bbs_SIZEOF16( uint32 ) +
					  bbs_SIZEOF16( uint32 ); /* version */

	memSizeL += bbs_SIZEOF16( ptrA->patchWidthE );
	memSizeL += bbs_SIZEOF16( ptrA->patchHeightE );
	memSizeL += bbs_SIZEOF16( ptrA->scaleExpE );
	memSizeL += bbs_SIZEOF16( ptrA->maxImageWidthE );
	memSizeL += bbs_SIZEOF16( ptrA->maxImageHeightE );
	memSizeL += bbs_SIZEOF16( ptrA->minScaleExpE );
	memSizeL += bbs_SIZEOF16( ptrA->maxRadiusE );

	return memSizeL; 
}

/* ------------------------------------------------------------------------- */
	
uint32 bbf_LocalScanner_memWrite( struct bbs_Context* cpA,
						     const struct bbf_LocalScanner* ptrA, 
						     uint16* memPtrA )
{
	uint32 memSizeL = bbf_LocalScanner_memSize( cpA, ptrA );
	memPtrA += bbs_memWrite32( &memSizeL, memPtrA );
	memPtrA += bbs_memWriteUInt32( bbf_LOCAL_SCANNER_VERSION, memPtrA );

	memPtrA += bbs_memWrite32( &ptrA->patchWidthE, memPtrA );
	memPtrA += bbs_memWrite32( &ptrA->patchHeightE, memPtrA );
	memPtrA += bbs_memWrite32( &ptrA->scaleExpE, memPtrA );
	memPtrA += bbs_memWrite32( &ptrA->maxImageWidthE, memPtrA );
	memPtrA += bbs_memWrite32( &ptrA->maxImageHeightE, memPtrA );
	memPtrA += bbs_memWrite32( &ptrA->minScaleExpE, memPtrA );
	memPtrA += bbs_memWrite32( &ptrA->maxRadiusE, memPtrA );
	return memSizeL;
}

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

uint32 bbf_LocalScanner_memRead( struct bbs_Context* cpA,
						    struct bbf_LocalScanner* ptrA, 
						    const uint16* memPtrA, 
						    struct bbs_MemTbl* mtpA )
{
	uint32 memSizeL, versionL;

	if( bbs_Context_error( cpA ) ) return 0;
	memPtrA += bbs_memRead32( &memSizeL, memPtrA );
	memPtrA += bbs_memReadVersion32( cpA, &versionL, bbf_LOCAL_SCANNER_VERSION, memPtrA );

	memPtrA += bbs_memRead32( &ptrA->patchWidthE, memPtrA );
	memPtrA += bbs_memRead32( &ptrA->patchHeightE, memPtrA );
	memPtrA += bbs_memRead32( &ptrA->scaleExpE, memPtrA );
	memPtrA += bbs_memRead32( &ptrA->maxImageWidthE, memPtrA );
	memPtrA += bbs_memRead32( &ptrA->maxImageHeightE, memPtrA );
	memPtrA += bbs_memRead32( &ptrA->minScaleExpE, memPtrA );
	memPtrA += bbs_memRead32( &ptrA->maxRadiusE, memPtrA );

	if( memSizeL != bbf_LocalScanner_memSize( cpA, ptrA ) )
	{
		bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bbf_LocalScanner_memRead( struct bem_ScanGradientMove* ptrA, const uint16* memPtrA ):\n"
			        "size mismatch" );
		return 0;
	}

	if( bbs_Context_error( cpA ) ) return 0;

	/* allocate arrays */
	bbf_LocalScanner_alloc( cpA, ptrA, mtpA );

	if( bbs_Context_error( cpA ) ) return 0;

	return memSizeL;
}

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

void bbf_LocalScanner_resetScan( struct bbs_Context* cpA,
								 struct bbf_LocalScanner* ptrA )
{
	ptrA->xE = ptrA->workScanRegionE.x1E;
	ptrA->yE = ptrA->workScanRegionE.y1E;
	bbf_LocalScanner_initPatchBuffer( cpA, ptrA );
}

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

void bbf_LocalScanner_assign( struct bbs_Context* cpA,
							  struct bbf_LocalScanner* ptrA,
							  const uint8* imagePtrA, 
							  uint32 imageWidthA,
							  uint32 imageHeightA,
							  const struct bbf_BitParam* paramPtrA )
{
	if( ptrA->scaleExpE == 0 ) 
	{
		ptrA->workImagePtrE = imagePtrA;
		ptrA->workWidthE = imageWidthA;
		ptrA->workHeightE = imageHeightA;
	}
	else
	{
		ptrA->origImagePtrE = imagePtrA;
		ptrA->origWidthE = imageWidthA;
		ptrA->origHeightE = imageHeightA;
	}

	ptrA->bitParamE = *paramPtrA;
	ptrA->xOffE = 0;
	ptrA->yOffE = 0;
	ptrA->origScanRegionE = bts_Int16Rect_create( 0, 0, imageWidthA, imageHeightA );
	bbf_LocalScanner_downscale( cpA, ptrA );
	bbf_LocalScanner_createBitImage( cpA, ptrA );
	bbf_LocalScanner_resetScan( cpA, ptrA );
}

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

const uint32* bbf_LocalScanner_getPatch( const struct bbf_LocalScanner* ptrA )
{
	return ptrA->patchBufferE.arrPtrE + ptrA->xE;
}

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

flag bbf_LocalScanner_next( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
{
	if( ( ptrA->xE + 1 ) < ptrA->workScanRegionE.x2E - ( int32 )ptrA->patchWidthE )
	{
		ptrA->xE++;
		return TRUE;
	}

	if( ( ptrA->yE + 1 ) >= ptrA->workScanRegionE.y2E - ( int32 )ptrA->patchHeightE ) return FALSE;

	ptrA->xE = ptrA->workScanRegionE.x1E;
	ptrA->yE++;

	{
		uint32 offL = ( ptrA->yE & 0x1F );
		uint32 rowL = ( ptrA->yE >> 5 ) + ( offL > 0 ? 1 : 0 );

		uint32 widthL = ptrA->bitImageE.widthE;
		uint32 sizeL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E;
		uint32* dstL = ( uint32* )ptrA->patchBufferE.arrPtrE + ptrA->xE;
		uint32 iL;

		if( rowL < ptrA->bitImageE.heightE )
		{
			uint32* srcL = ptrA->bitImageE.arrE.arrPtrE + rowL * widthL + ptrA->xE;
			if( offL > 0 )
			{
				uint32 shlL = 32 - offL;
				for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] = ( dstL[ iL ] >> 1 ) | ( srcL[ iL ] << shlL );
			}
			else
			{
				bbs_memcpy32( dstL, srcL, sizeL );
			}
		}
		else
		{
			for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] >>= 1;
		}
	}

	return TRUE;
}

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

void bbf_LocalScanner_goToXY( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA, int32 xA, int32 yA )
{
	bbs_DEF_fNameL( "void bbf_LocalScanner_goToXY( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA, int32 xA, int32 yA )" )
	if( xA < ptrA->workScanRegionE.x1E || xA >= ptrA->workScanRegionE.x2E - ( int32 )ptrA->patchWidthE )
	{
		bbs_ERROR1( "%s:\nxA out of range", fNameL );
		return;
	}
	ptrA->xE = xA;
	if( ptrA->yE == yA ) return;
	if( yA < ptrA->workScanRegionE.y1E || yA >= ptrA->workScanRegionE.y2E - ( int32 )ptrA->patchHeightE )
	{
		bbs_ERROR1( "%s:\nyA out of range", fNameL );
		return;
	}
	ptrA->yE = yA;

	{
		uint32 offL = ( ptrA->yE & 0x1F );
		uint32 rowL = ( ptrA->yE >> 5 ) + ( offL > 0 ? 1 : 0 );

		uint32 sizeL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E;
		uint32 imgWidthL = ptrA->bitImageE.widthE;
		uint32 imgOffsL = ptrA->workScanRegionE.x1E;
		uint32* dstL = ptrA->patchBufferE.arrPtrE + imgOffsL;
		uint32 iL;

		if( rowL < ptrA->bitImageE.heightE )
		{
			if( offL > 0 )
			{
				uint32* src1L = ptrA->bitImageE.arrE.arrPtrE + rowL * imgWidthL + imgOffsL;
				uint32* src0L = src1L - imgWidthL;
				uint32 shlL = 32 - offL;
				for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] = ( src0L[ iL ] >> offL ) | ( src1L[ iL ] << shlL );
			}
			else
			{
				bbs_memcpy32( dstL, ptrA->bitImageE.arrE.arrPtrE + rowL * imgWidthL + imgOffsL, sizeL );
			}
		}
		else
		{
			uint32* srcL = ptrA->bitImageE.arrE.arrPtrE + ( rowL - 1 ) * imgWidthL + imgOffsL;
			for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] = srcL[ iL ] >> offL;
		}
	}
}

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

void bbf_LocalScanner_goToIndex( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA, uint32 scanIndexA )
{
	uint32 wL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E - ptrA->patchWidthE;
	bbf_LocalScanner_goToXY( cpA, ptrA,
							 ( scanIndexA % wL ) + ptrA->workScanRegionE.x1E, 
							 ( scanIndexA / wL ) + ptrA->workScanRegionE.y1E ); 
}

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

flag bbf_LocalScanner_nextOffset( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
{
	int32 maxL = ( 1 << ptrA->scaleExpE );
	if( ptrA->yOffE == maxL ) return FALSE;

	ptrA->xOffE++;

	if( ptrA->xOffE == maxL )
	{
		ptrA->xOffE = 0;
		ptrA->yOffE++;
		if( ptrA->yOffE == maxL ) return FALSE;
	}

	bbf_LocalScanner_downscale( cpA, ptrA );
	bbf_LocalScanner_createBitImage( cpA, ptrA );
	bbf_LocalScanner_setWorkScanRegion( cpA, ptrA );
	bbf_LocalScanner_resetScan( cpA, ptrA );

	return TRUE;
}

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

/* ========================================================================= */