1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* ---- includes ----------------------------------------------------------- */
18
19#include "b_BasicEm/Functions.h"
20#include "b_BasicEm/Math.h"
21#include "b_BitFeatureEm/Scanner.h"
22
23/* ------------------------------------------------------------------------- */
24
25/* ========================================================================= */
26/*                                                                           */
27/* ---- \ghd{ auxiliary functions } ---------------------------------------- */
28/*                                                                           */
29/* ========================================================================= */
30
31/* ------------------------------------------------------------------------- */
32
33/** multiplies a scale with a 0.32 scale factor */
34uint32 bbf_Scanner_scalePrd( uint32 scaleA, uint32 factorA /*0.32 */ )\
35{
36	return      ( scaleA >> 16     ) * ( factorA >> 16     ) +
37			( ( ( scaleA & 0x0FFFF ) * ( factorA >> 16     ) ) >> 16 ) +
38			( ( ( scaleA >> 16     ) * ( factorA & 0x0FFFF ) ) >> 16 );
39}
40
41/* ------------------------------------------------------------------------- */
42
43/** allocates arays */
44void bbf_Scanner_alloc( struct bbs_Context* cpA,
45						struct bbf_Scanner* ptrA,
46						struct bbs_MemTbl* mtpA,
47						flag maximizeSharedMemoryA )
48{
49	struct bbs_MemTbl memTblL = *mtpA;
50	struct bbs_MemSeg* espL = bbs_MemTbl_segPtr( cpA, &memTblL, 0 );
51	struct bbs_MemSeg* sspL = bbs_MemTbl_sharedSegPtr( cpA, &memTblL, 0 );
52	struct bbs_MemSeg* mspL = maximizeSharedMemoryA ? sspL : espL;
53
54	/* filter patch dimension */
55	uint32 proL = ptrA->maxRadiusE;
56	uint32 pwoL = ( proL << 1 ) + 1;
57
58	/* output image size (bit image) */
59	uint32 woL = ptrA->maxImageWidthE;
60	uint32 hoL = ptrA->maxImageHeightE;
61
62	/* extended output image size (bit image) considering borders */
63	uint32 xwoL = woL + ( ptrA->borderWidthE  << 1 );
64	uint32 xhoL = hoL + ( ptrA->borderHeightE << 1 );
65
66	/* allocate working image */
67	bbs_UInt16Arr_create( cpA, &ptrA->workImageE, ( ( woL >> 1 ) + ( woL & 1 ) ) * hoL, mspL );
68	if( bbs_Context_error( cpA ) ) return;
69	bbs_UInt16Arr_fill( cpA, &ptrA->workImageE, 0 );
70
71	/* allocate bit image */
72	bim_UInt32Image_create( cpA, &ptrA->bitImageE, xwoL, ( xhoL >> 5 ) + ( ( ( xhoL & 0x1F ) != 0 ) ? 1 : 0 ), mspL );
73	if( bbs_Context_error( cpA ) ) return;
74	bim_UInt32Image_setAllPixels( cpA, &ptrA->bitImageE, 0, 0 );
75
76	/* allocate patch buffer */
77	bbs_UInt32Arr_create( cpA, &ptrA->patchBufferE, ptrA->bitImageE.widthE, mspL );
78	if( bbs_Context_error( cpA ) ) return;
79	bbs_UInt32Arr_fill( cpA, &ptrA->patchBufferE, 0 );
80
81	/* allocate line buffer */
82	bbs_UInt16Arr_create( cpA, &ptrA->lineBufE, woL + ( woL & 1 ), sspL );
83
84	/* allocate table */
85	bim_UInt32Image_create( cpA, &ptrA->satE, woL + pwoL, pwoL + 1, sspL );
86
87	/* allocate buffers */
88	bbs_UInt32Arr_create( cpA, &ptrA->idxArrE, ptrA->bufferSizeE, mspL );
89	bbs_Int32Arr_create(  cpA, &ptrA->actArrE, ptrA->bufferSizeE, mspL );
90
91	bbs_Int32Arr_create(  cpA, &ptrA->outArrE, ptrA->bufferSizeE >> 1, espL );
92}
93
94/* ------------------------------------------------------------------------- */
95
96/** downscales work image */
97void bbf_Scanner_downscale( struct bbs_Context* cpA, struct bbf_Scanner* ptrA )
98{
99	uint32 w0L = ptrA->workWidthE;
100	uint32 h0L = ptrA->workHeightE;
101	uint32 w1L = w0L >> 1;
102	uint32 h1L = h0L >> 1;
103	uint32 w20L = ( w0L >> 1 ) + ( w0L & 1 );
104	uint16* arrL = ptrA->workImageE.arrPtrE;
105
106	uint32 iL, jL;
107	uint32 kL = 0;
108	for( jL = 0; jL < h1L; jL++ )
109	{
110		for( iL = 0; iL < ( w1L >> 1 ); iL++ )
111		{
112			uint16 loL, hiL;
113			uint32 idxL = jL * 2 * w20L + iL * 2;
114
115			loL = ( ( arrL[ idxL ] & 0x00FF ) + ( arrL[ idxL ] >> 8 ) + ( arrL[ idxL + w20L ] & 0x00FF ) + ( arrL[ idxL + w20L ] >> 8 ) + 2 ) >> 2;
116			idxL++;
117			hiL = ( ( arrL[ idxL ] & 0x00FF ) + ( arrL[ idxL ] >> 8 ) + ( arrL[ idxL + w20L ] & 0x00FF ) + ( arrL[ idxL + w20L ] >> 8 ) + 2 ) >> 2;
118
119			arrL[ kL ] = loL | ( hiL << 8 );
120			kL++;
121		}
122		if( ( w1L & 1 ) != 0 )
123		{
124			uint32 idxL = jL * 2 * w20L + iL;
125			arrL[ kL++ ] = ( ( arrL[ idxL ] & 0x00FF ) + ( arrL[ idxL ] >> 8 ) + ( arrL[ idxL + w20L ] & 0x00FF ) + ( arrL[ idxL + w20L ] >> 8 ) + 2 ) >> 2;
126		}
127	}
128
129	ptrA->workWidthE = w1L;
130	ptrA->workHeightE = h1L;
131	ptrA->scaleExpE++;
132}
133
134/* ------------------------------------------------------------------------- */
135
136/** copies image
137 * handling for 8 bit images is implemented
138 * 16 bit image handling for the whole class needs to be added in this function only
139 */
140void bbf_Scanner_copyImage( struct bbs_Context* cpA, struct bbf_Scanner* ptrA, const void* imagePtrA, uint32 imageWidthA, uint32 imageHeightA, const struct bts_Int16Rect* roiPtrA )
141{
142	bbs_DEF_fNameL( "void bbf_Scanner_copyImage( struct bbs_Context* cpA, struct bbf_Scanner* ptrA, const struct bim_UInt16ByteImage* imagePtrA, const struct bts_Int16Rect* roiPtrA )" )
143
144	if( imageWidthA > ptrA->maxImageWidthE || imageHeightA > ptrA->maxImageHeightE )
145	{
146		bbs_ERROR5( "%s:\n Input image (%ix%i)is too large; Scanner is configured for maximal (%ix%i)",
147			fNameL, imageWidthA, imageHeightA, ptrA->maxImageWidthE, ptrA->maxImageHeightE );
148		return;
149	}
150
151	if( roiPtrA == 0 )
152	{
153		uint32 iL, jL;
154		const uint8*  srcL = ( uint8* )imagePtrA;
155		uint16* dstL = ptrA->workImageE.arrPtrE;
156		ptrA->workWidthE  = imageWidthA;
157		ptrA->workHeightE = imageHeightA;
158		for( iL = 0; iL < ptrA->workHeightE; iL++ )
159		{
160			for( jL = ptrA->workWidthE >> 1; jL > 0; jL-- )
161			{
162				*dstL++ = ( uint16 )srcL[ 0 ] | ( uint16 )srcL[ 1 ] << 8;
163				srcL += 2;
164			}
165
166			/* uneven width */
167			if( ptrA->workWidthE & 1 ) *dstL++ = *srcL++;
168		}
169	}
170	else
171	{
172		uint32 iL, jL;
173		const uint8* srcL = ( uint8* )imagePtrA + roiPtrA->y1E * imageWidthA + roiPtrA->x1E;
174		uint16* dstL = ptrA->workImageE.arrPtrE;
175
176		if( roiPtrA->x2E <= roiPtrA->x1E || roiPtrA->y2E <= roiPtrA->y1E )
177		{
178			bbs_ERROR1( "%s:\n ROI is invalid or zero", fNameL );
179			return;
180		}
181		if( roiPtrA->x1E < 0 || roiPtrA->y1E < 0 || roiPtrA->x2E > ( int32 )imageWidthA || roiPtrA->y2E > ( int32 )imageHeightA )
182		{
183			bbs_ERROR1( "%s:\n ROI exceeds image boundary", fNameL );
184			return;
185		}
186
187		ptrA->workWidthE  = roiPtrA->x2E - roiPtrA->x1E;
188		ptrA->workHeightE = roiPtrA->y2E - roiPtrA->y1E;
189		for( iL = 0; iL < ptrA->workHeightE; iL++ )
190		{
191			for( jL = ptrA->workWidthE >> 1; jL > 0; jL-- )
192			{
193				*dstL++ = ( uint16 )srcL[ 0 ] | ( uint16 )srcL[ 1 ] << 8;
194				srcL += 2;
195			}
196
197			/* uneven width */
198			if( ptrA->workWidthE & 1 ) *dstL++ = *srcL++;
199
200			srcL += imageWidthA - ptrA->workWidthE;
201		}
202	}
203}
204
205/* ------------------------------------------------------------------------- */
206
207/** creates bit image */
208void bbf_Scanner_createBitImage( struct bbs_Context* cpA, struct bbf_Scanner* ptrA )
209{
210	bbs_DEF_fNameL( "void bbf_Scanner_createBitImage( struct bbs_Context* cpA, struct bbf_Scanner* ptrA )" )
211
212
213	/* declarations */
214	uint32 proL, priL, pwoL, pwiL;
215	uint32 wiL, wi2L, hiL, woL, hoL, xwoL, xhoL; /* image size specifies */
216	uint32 stepL;    /* scan step (16.16) */
217	uint32 bitMaskL; /* current bit mask */
218	uint32* bitRowL; /* pointer to bit-row */
219	uint32 wsL, hsL; /* size of summed area table (ringbuffer) */
220	uint32 satSizeL;
221	uint32* satL;     /* pointer to summed area table */
222	uint16* lBufL;	  /* pointer to line buffer */
223	uint32 yfL;       /* fixed point y-coordinate (16.16) */
224	uint32 iL, jL;
225
226	uint32 swi1L; /* table writing index */
227	uint32 swi2L; /* table writing index */
228	uint32 sriL;  /* table reading index */
229
230	uint32 poAreaL, piAreaL; /* areas of inner and outer rectangles */
231	uint32 siL[ 8 ]; /* table indices */
232
233
234	proL = ptrA->bitParamE.outerRadiusE;
235	priL = ptrA->bitParamE.innerRadiusE;
236	pwoL = ( proL << 1 ) + 1;
237	pwiL = ( priL << 1 ) + 1;
238
239	if( ptrA->borderHeightE >= 32 )
240	{
241		bbs_ERROR1( "%s:\n borderHeightE >= 32", fNameL );
242		return;
243	}
244
245	if( proL <= priL )
246	{
247		bbs_ERROR1( "%s:\n outer radius <= inner radius", fNameL );
248		return;
249	}
250
251	/* input image size (bit image) */
252	wiL = ptrA->workWidthE;
253	hiL = ptrA->workHeightE;
254	wi2L = ( wiL >> 1 ) + ( wiL & 1 );
255
256	/* 16.16 */
257	stepL = ptrA->scaleE >> ( ptrA->scaleExpE + 4 );
258
259	/* output image size (bit image) */
260	woL = ( wiL << 16 ) / stepL;
261	hoL = ( hiL << 16 ) / stepL;
262
263	if( woL <= pwoL || hoL <= pwoL )
264	{
265		bbs_ERROR1( "%s:\n scaled image is too small", fNameL );
266		return;
267	}
268
269	if( woL * stepL >= ( wiL << 16 ) ) woL--;
270	if( hoL * stepL >= ( hiL << 16 ) ) hoL--;
271
272	/* extended output image size (bit image) considering borders */
273	xwoL = woL + ( ptrA->borderWidthE  << 1 );
274	xhoL = hoL + ( ptrA->borderHeightE << 1 );
275
276	ptrA->currentWidthE  = xwoL;
277	ptrA->currentHeightE = xhoL;
278
279	/* initialize bit image */
280	bim_UInt32Image_size( cpA, &ptrA->bitImageE, xwoL, ( xhoL >> 5 ) + ( ( ( xhoL & 0x1F ) != 0 ) ? 1 : 0 ) );
281	bim_UInt32Image_setAllPixels( cpA, &ptrA->bitImageE, 0, 0 );
282
283	bitMaskL = ( uint32 )1 << ptrA->borderHeightE;
284	bitRowL = ( uint32* )ptrA->bitImageE.arrE.arrPtrE + ptrA->borderWidthE;
285
286	/* width of table */
287	wsL = woL + pwoL;
288
289	/* height of table */
290	hsL = pwoL + 1;
291
292	bim_UInt32Image_size( cpA, &ptrA->satE, wsL, hsL );
293
294	satL = ptrA->satE.arrE.arrPtrE;
295	satSizeL = wsL * hsL;
296
297	lBufL = ptrA->lineBufE.arrPtrE;
298
299	yfL = 0; /* fixed point y-coordinate ( 16.16 )*/
300
301	swi1L = 0; /* table writing index */
302	swi2L = 0; /* table writing index */
303	sriL = 0;  /* table reading index */
304
305	/* areas of inner and outer rectangles */
306	poAreaL = pwoL * pwoL;
307	piAreaL = pwiL * pwiL;
308
309	/* interpolate pixels; compute table and bit image */
310
311	for( iL = wsL * ( proL + 1 ); iL > 0; iL-- ) satL[ swi1L++ ] = 0;
312	swi2L = swi1L - wsL;
313
314	for( jL = 0; jL < hoL + proL; jL++ )
315	{
316		if( jL < hoL ) /* rescale area */
317		{
318			uint32 ypL = ( yfL >> 16 );
319			uint32 yoff1L = yfL & 0x0FFFF;
320			uint32 yoff0L = 0x010000 - yoff1L;
321			const uint16* arr0L = ptrA->workImageE.arrPtrE + ypL * wi2L;
322			const uint16* arr1L = arr0L + wi2L;
323
324
325			uint32 xfL   = 0; /* fixed point x-coordinate (16.16) */
326			uint32 hSumL = 0;
327
328			yfL += stepL;
329
330			for( iL = 0; iL <= proL; iL++ ) satL[ swi1L++ ] = 0;
331			swi2L += iL;
332
333			/* fill line buffer */
334			for( iL = 0; iL < wi2L; iL++ )
335			{
336				lBufL[ iL * 2     ] = ( ( ( arr0L[ iL ] & 0x0FF ) * yoff0L ) + ( ( arr1L[ iL ] & 0x0FF ) * yoff1L ) ) >> 10;
337				lBufL[ iL * 2 + 1 ] = ( ( ( arr0L[ iL ] >> 8    ) * yoff0L ) + ( ( arr1L[ iL ] >> 8    ) * yoff1L ) ) >> 10;
338			}
339
340			for( iL = 0; iL < woL; iL++ )
341			{
342				uint32 xpL = ( xfL >> 16 );
343				uint32 xoff1L = xfL & 0x0FFFF;
344				uint16 pixL = ( lBufL[ xpL ] * ( 0x010000 - xoff1L ) + lBufL[ xpL + 1 ] * xoff1L ) >> 22;
345				satL[ swi1L ] = ( hSumL += pixL ) + satL[ swi2L ];
346				xfL += stepL;
347				swi1L++;
348				swi2L++;
349			}
350
351			for( iL = 0; iL < proL; iL++ )
352			{
353				satL[ swi1L ] = hSumL + satL[ swi2L ];
354				swi1L++;
355				swi2L++;
356			}
357		}
358		else /* image is processed - fill in 0s */
359		{
360			for( iL = 0; iL < wsL; iL++ ) satL[ swi1L++ ] = satL[ swi2L++ ];
361		}
362
363		swi1L = ( swi1L < satSizeL ) ? swi1L : 0;
364		swi2L = ( swi2L < satSizeL ) ? swi2L : 0;
365
366		/* fill line in bit image */
367		if( jL >= proL )
368		{
369			const uint32* rSatL = satL;
370
371			/* table coordinate indices for outer rectangle */
372			siL[ 0 ] = sriL;
373			siL[ 1 ] = siL[ 0 ] + pwoL;
374			siL[ 2 ] = siL[ 0 ] + pwoL * wsL;
375			siL[ 2 ] -= ( siL[ 2 ] >= satSizeL ) ? satSizeL : 0;
376			siL[ 3 ] = siL[ 2 ] + pwoL;
377
378			/* table coordinate indices for inner rectangle */
379			siL[ 4 ] = siL[ 0 ] + ( proL - priL ) * wsL + ( proL - priL );
380			siL[ 4 ] -= ( siL[ 4 ] >= satSizeL ) ? satSizeL : 0;
381			siL[ 5 ] = siL[ 4 ] + pwiL;
382			siL[ 6 ] = siL[ 4 ] + pwiL * wsL;
383			siL[ 6 ] -= ( siL[ 6 ] >= satSizeL ) ? satSizeL : 0;
384			siL[ 7 ] = siL[ 6 ] + pwiL;
385			sriL += wsL;
386			if( sriL == satSizeL ) sriL = 0;
387
388			for( iL = 0; iL < woL; iL++ )
389			{
390				uint32 oAvgL = ( rSatL[ siL[ 0 ] ] - rSatL[ siL[ 1 ] ] - rSatL[ siL[ 2 ] ] + rSatL[ siL[ 3 ] ] ) * piAreaL;
391				uint32 iAvgL = ( rSatL[ siL[ 4 ] ] - rSatL[ siL[ 5 ] ] - rSatL[ siL[ 6 ] ] + rSatL[ siL[ 7 ] ] ) * poAreaL;
392				bitRowL[ iL ] |= ( iAvgL > oAvgL ) ? bitMaskL : 0;
393				rSatL++;
394			}
395			if( ( bitMaskL <<= 1 ) == 0 )
396			{
397				bitRowL += xwoL;
398				bitMaskL = 1;
399			}
400		}
401	}
402}
403
404/* ------------------------------------------------------------------------- */
405
406/** initialize patch buffer */
407void bbf_Scanner_initPatchBuffer( struct bbs_Context* cpA, struct bbf_Scanner* ptrA )
408{
409	bbs_UInt32Arr_size( cpA, &ptrA->patchBufferE, ptrA->bitImageE.widthE );
410	bbs_memcpy32( ptrA->patchBufferE.arrPtrE, ptrA->bitImageE.arrE.arrPtrE, ptrA->bitImageE.widthE );
411}
412
413/* ------------------------------------------------------------------------- */
414
415/* ========================================================================= */
416/*                                                                           */
417/* ---- \ghd{ constructor / destructor } ----------------------------------- */
418/*                                                                           */
419/* ========================================================================= */
420
421/* ------------------------------------------------------------------------- */
422
423void bbf_Scanner_init( struct bbs_Context* cpA,
424					   struct bbf_Scanner* ptrA )
425{
426	ptrA->scaleExpE = 0;
427	ptrA->scaleE = 0;
428	ptrA->xE = 0;
429	ptrA->yE = 0;
430	ptrA->effMaxScaleE = 0;
431	ptrA->currentWidthE = 0;
432	ptrA->currentHeightE = 0;
433	ptrA->workWidthE = 0;
434	ptrA->workHeightE = 0;
435	bbf_BitParam_init( cpA, &ptrA->bitParamE );
436	bbs_UInt16Arr_init( cpA, &ptrA->workImageE );
437	bim_UInt32Image_init( cpA, &ptrA->satE );
438	bim_UInt32Image_init( cpA, &ptrA->bitImageE );
439	bbs_UInt32Arr_init( cpA, &ptrA->patchBufferE );
440	bbs_UInt16Arr_init( cpA, &ptrA->lineBufE );
441
442	bbs_UInt32Arr_init( cpA, &ptrA->idxArrE );
443	bbs_Int32Arr_init( cpA, &ptrA->actArrE );
444	bbs_Int32Arr_init( cpA, &ptrA->outArrE );
445	ptrA->outCountE = 0;
446	ptrA->intCountE = 0;
447	ptrA->bufferSizeE = 1024;
448
449	ptrA->maxImageWidthE = 0;
450	ptrA->maxImageHeightE = 0;
451	ptrA->maxRadiusE = 0;
452	ptrA->patchWidthE = 0;
453	ptrA->patchHeightE = 0;
454	ptrA->minScaleE = 0;
455	ptrA->maxScaleE = 0;
456	ptrA->scaleStepE = 0;
457	ptrA->borderWidthE = 0;
458	ptrA->borderHeightE = 0;
459}
460
461/* ------------------------------------------------------------------------- */
462
463void bbf_Scanner_exit( struct bbs_Context* cpA,
464				       struct bbf_Scanner* ptrA )
465{
466	ptrA->scaleExpE = 0;
467	ptrA->scaleE = 0;
468	ptrA->xE = 0;
469	ptrA->yE = 0;
470	ptrA->effMaxScaleE = 0;
471	ptrA->currentWidthE = 0;
472	ptrA->currentHeightE = 0;
473	ptrA->workWidthE = 0;
474	ptrA->workHeightE = 0;
475	bbf_BitParam_exit( cpA, &ptrA->bitParamE );
476	bbs_UInt16Arr_exit( cpA, &ptrA->workImageE );
477	bim_UInt32Image_exit( cpA, &ptrA->satE );
478	bim_UInt32Image_exit( cpA, &ptrA->bitImageE );
479	bbs_UInt32Arr_exit( cpA, &ptrA->patchBufferE );
480	bbs_UInt16Arr_exit( cpA, &ptrA->lineBufE );
481
482	bbs_UInt32Arr_exit( cpA, &ptrA->idxArrE );
483	bbs_Int32Arr_exit( cpA, &ptrA->actArrE );
484	bbs_Int32Arr_exit( cpA, &ptrA->outArrE );
485	ptrA->outCountE = 0;
486	ptrA->intCountE = 0;
487	ptrA->bufferSizeE = 1024;
488
489	ptrA->maxImageWidthE = 0;
490	ptrA->maxImageHeightE = 0;
491	ptrA->maxRadiusE = 0;
492	ptrA->patchWidthE = 0;
493	ptrA->patchHeightE = 0;
494	ptrA->minScaleE = 0;
495	ptrA->maxScaleE = 0;
496	ptrA->scaleStepE = 0;
497	ptrA->borderWidthE = 0;
498	ptrA->borderHeightE = 0;
499}
500
501/* ------------------------------------------------------------------------- */
502
503/* ========================================================================= */
504/*                                                                           */
505/* ---- \ghd{ operators } -------------------------------------------------- */
506/*                                                                           */
507/* ========================================================================= */
508
509/* ------------------------------------------------------------------------- */
510
511void bbf_Scanner_copy( struct bbs_Context* cpA,
512				       struct bbf_Scanner* ptrA,
513					   const struct bbf_Scanner* srcPtrA )
514{
515	ptrA->scaleExpE = srcPtrA->scaleExpE;
516	ptrA->scaleE = srcPtrA->scaleE;
517	ptrA->xE = srcPtrA->xE;
518	ptrA->yE = srcPtrA->yE;
519	ptrA->effMaxScaleE = srcPtrA->effMaxScaleE;
520	ptrA->currentWidthE = srcPtrA->currentWidthE;
521	ptrA->currentHeightE = srcPtrA->currentHeightE;
522	ptrA->workWidthE = srcPtrA->workWidthE;
523	ptrA->workHeightE = srcPtrA->workHeightE;
524
525	bbf_BitParam_copy( cpA, &ptrA->bitParamE, &srcPtrA->bitParamE );
526	bbs_UInt16Arr_copy( cpA, &ptrA->workImageE, &srcPtrA->workImageE );
527	bim_UInt32Image_copy( cpA, &ptrA->satE, &srcPtrA->satE );
528	bim_UInt32Image_copy( cpA, &ptrA->bitImageE, &srcPtrA->bitImageE );
529	bbs_UInt32Arr_copy( cpA, &ptrA->patchBufferE, &srcPtrA->patchBufferE );
530	bbs_UInt16Arr_copy( cpA, &ptrA->lineBufE, &srcPtrA->lineBufE );
531
532	ptrA->maxImageWidthE = srcPtrA->maxImageWidthE;
533	ptrA->maxImageHeightE = srcPtrA->maxImageHeightE;
534	ptrA->maxRadiusE = srcPtrA->maxRadiusE;
535	ptrA->patchWidthE = srcPtrA->patchWidthE;
536	ptrA->patchHeightE = srcPtrA->patchHeightE;
537	ptrA->minScaleE = srcPtrA->minScaleE;
538	ptrA->maxScaleE = srcPtrA->maxScaleE;
539	ptrA->scaleStepE = srcPtrA->scaleStepE;
540	ptrA->borderWidthE = srcPtrA->borderWidthE;
541	ptrA->borderHeightE = srcPtrA->borderHeightE;
542}
543
544/* ------------------------------------------------------------------------- */
545
546flag bbf_Scanner_equal( struct bbs_Context* cpA,
547				        const struct bbf_Scanner* ptrA,
548						const struct bbf_Scanner* srcPtrA )
549{
550	if( ptrA->maxImageWidthE != srcPtrA->maxImageWidthE ) return FALSE;
551	if( ptrA->maxImageHeightE != srcPtrA->maxImageHeightE ) return FALSE;
552	if( ptrA->maxRadiusE != srcPtrA->maxRadiusE ) return FALSE;
553	if( ptrA->patchWidthE != srcPtrA->patchWidthE ) return FALSE;
554	if( ptrA->patchHeightE != srcPtrA->patchHeightE ) return FALSE;
555	if( ptrA->minScaleE != srcPtrA->minScaleE ) return FALSE;
556	if( ptrA->maxScaleE != srcPtrA->maxScaleE ) return FALSE;
557	if( ptrA->scaleStepE != srcPtrA->scaleStepE ) return FALSE;
558	if( ptrA->borderWidthE != srcPtrA->borderWidthE ) return FALSE;
559	if( ptrA->borderHeightE != srcPtrA->borderHeightE ) return FALSE;
560	return TRUE;
561}
562
563/* ------------------------------------------------------------------------- */
564
565/* ========================================================================= */
566/*                                                                           */
567/* ---- \ghd{ query functions } -------------------------------------------- */
568/*                                                                           */
569/* ========================================================================= */
570
571/* ------------------------------------------------------------------------- */
572
573uint32 bbf_Scanner_positions( const struct bbf_Scanner* ptrA )
574{
575	int32 wL = ( int32 )ptrA->currentWidthE - ptrA->patchWidthE;
576	int32 hL = ( int32 )ptrA->currentHeightE - ptrA->patchHeightE;
577	return ( wL >= 0 ? wL : 0 ) * ( hL >= 0 ? hL : 0 );
578}
579
580/* ------------------------------------------------------------------------- */
581
582uint32 bbf_Scanner_scanIndex( const struct bbf_Scanner* ptrA )
583{
584	return ptrA->yE * ptrA->currentWidthE + ptrA->xE;
585}
586
587/* ------------------------------------------------------------------------- */
588
589void bbf_Scanner_pos( const struct bbf_Scanner* ptrA,
590					  int32* xPtrA, int32* yPtrA, uint32* scalePtrA )
591{
592	/* 16.16 */
593	*xPtrA = ( int32 )( ptrA->xE - ptrA->borderWidthE ) * ( int32 )( ptrA->scaleE >> 4 );
594
595	/* 16.16 */
596	*yPtrA = ( int32 )( ptrA->yE - ptrA->borderHeightE ) * ( int32 )( ptrA->scaleE >> 4 );
597
598	/* 12.20 */
599	*scalePtrA = ptrA->scaleE;
600}
601
602/* ------------------------------------------------------------------------- */
603
604void bbf_Scanner_idxPos( const struct bbf_Scanner* ptrA, uint32 scanIndexA,
605					     int32* xPtrA, int32* yPtrA, uint32* scalePtrA )
606{
607	int32 yL = scanIndexA / ptrA->currentWidthE;
608	int32 xL = scanIndexA - ( yL * ptrA->currentWidthE );
609
610	/* 16.16 */
611	*xPtrA = ( int32 )( xL - ptrA->borderWidthE  ) * ( int32 )( ptrA->scaleE >> 4 );
612
613	/* 16.16 */
614	*yPtrA = ( int32 )( yL - ptrA->borderHeightE ) * ( int32 )( ptrA->scaleE >> 4 );
615
616	*scalePtrA = ptrA->scaleE;
617}
618
619/* ------------------------------------------------------------------------- */
620
621/* ========================================================================= */
622/*                                                                           */
623/* ---- \ghd{ modify functions } ------------------------------------------- */
624/*                                                                           */
625/* ========================================================================= */
626
627/* ------------------------------------------------------------------------- */
628
629void bbf_Scanner_create( struct bbs_Context* cpA,
630						 struct bbf_Scanner* ptrA,
631						 flag maximizeSharedMemoryA,
632						 uint32 maxImageWidthA,
633					 	 uint32 maxImageHeightA,
634						 uint32 maxRadiusA,
635						 uint32 patchWidthA,
636						 uint32 patchHeightA,
637						 uint32 minScaleA,
638						 uint32 maxScaleA,
639						 uint32 scaleStepA,
640						 uint32 borderWidthA,
641						 uint32 borderHeightA,
642						 uint32 bufferSizeA,
643						 struct bbs_MemTbl* mtpA )
644{
645	ptrA->maxImageWidthE = maxImageWidthA;
646	ptrA->maxImageHeightE = maxImageHeightA;
647	ptrA->maxRadiusE = maxRadiusA;
648	ptrA->patchWidthE = patchWidthA;
649	ptrA->patchHeightE = patchHeightA;
650	ptrA->minScaleE = minScaleA;
651	ptrA->maxScaleE = maxScaleA;
652	ptrA->scaleStepE = scaleStepA;
653	ptrA->borderWidthE = borderWidthA;
654	ptrA->borderHeightE = borderHeightA;
655	ptrA->bufferSizeE = bufferSizeA;
656	bbf_Scanner_alloc( cpA, ptrA, mtpA, maximizeSharedMemoryA );
657}
658
659/* ------------------------------------------------------------------------- */
660
661void bbf_Scanner_bitParam( struct bbs_Context* cpA,
662						   struct bbf_Scanner* ptrA,
663						   const struct bbf_BitParam* bitParamPtrA )
664{
665	if( !bbf_BitParam_equal( cpA, &ptrA->bitParamE, bitParamPtrA ) )
666	{
667		bbf_BitParam_copy( cpA, &ptrA->bitParamE, bitParamPtrA );
668		bbf_Scanner_createBitImage( cpA, ptrA );
669	}
670
671	bbf_Scanner_resetScan( cpA, ptrA );
672}
673
674/* ------------------------------------------------------------------------- */
675
676/* ========================================================================= */
677/*                                                                           */
678/* ---- \ghd{ I/O } -------------------------------------------------------- */
679/*                                                                           */
680/* ========================================================================= */
681
682/* ------------------------------------------------------------------------- */
683
684uint32 bbf_Scanner_memSize( struct bbs_Context* cpA,
685							const struct bbf_Scanner* ptrA )
686{
687	uint32 memSizeL = bbs_SIZEOF16( uint32 ) +
688					  bbs_SIZEOF16( uint32 ); /* version */
689	memSizeL += bbs_SIZEOF16( ptrA->maxImageWidthE );
690	memSizeL += bbs_SIZEOF16( ptrA->maxImageHeightE );
691	memSizeL += bbs_SIZEOF16( ptrA->maxRadiusE );
692	memSizeL += bbs_SIZEOF16( ptrA->patchWidthE );
693	memSizeL += bbs_SIZEOF16( ptrA->patchHeightE );
694	memSizeL += bbs_SIZEOF16( ptrA->minScaleE );
695	memSizeL += bbs_SIZEOF16( ptrA->maxScaleE );
696	memSizeL += bbs_SIZEOF16( ptrA->scaleStepE );
697	memSizeL += bbs_SIZEOF16( ptrA->borderWidthE );
698	memSizeL += bbs_SIZEOF16( ptrA->borderHeightE );
699	return memSizeL;
700}
701
702/* ------------------------------------------------------------------------- */
703
704uint32 bbf_Scanner_memWrite( struct bbs_Context* cpA,
705						     const struct bbf_Scanner* ptrA,
706						     uint16* memPtrA )
707{
708	uint32 memSizeL = bbf_Scanner_memSize( cpA, ptrA );
709	memPtrA += bbs_memWrite32( &memSizeL, memPtrA );
710	memPtrA += bbs_memWriteUInt32( bbf_SCANNER_VERSION, memPtrA );
711	memPtrA += bbs_memWrite32( &ptrA->maxImageWidthE, memPtrA );
712	memPtrA += bbs_memWrite32( &ptrA->maxImageHeightE, memPtrA );
713	memPtrA += bbs_memWrite32( &ptrA->maxRadiusE, memPtrA );
714	memPtrA += bbs_memWrite32( &ptrA->patchWidthE, memPtrA );
715	memPtrA += bbs_memWrite32( &ptrA->patchHeightE, memPtrA );
716	memPtrA += bbs_memWrite32( &ptrA->minScaleE, memPtrA );
717	memPtrA += bbs_memWrite32( &ptrA->maxScaleE, memPtrA );
718	memPtrA += bbs_memWrite32( &ptrA->scaleStepE, memPtrA );
719	memPtrA += bbs_memWrite32( &ptrA->borderWidthE, memPtrA );
720	memPtrA += bbs_memWrite32( &ptrA->borderHeightE, memPtrA );
721	return memSizeL;
722}
723
724/* ------------------------------------------------------------------------- */
725
726uint32 bbf_Scanner_memRead( struct bbs_Context* cpA,
727						    struct bbf_Scanner* ptrA,
728						    const uint16* memPtrA,
729						    struct bbs_MemTbl* mtpA )
730{
731	uint32 memSizeL, versionL;
732
733	if( bbs_Context_error( cpA ) ) return 0;
734	memPtrA += bbs_memRead32( &memSizeL, memPtrA );
735	memPtrA += bbs_memReadVersion32( cpA, &versionL, bbf_SCANNER_VERSION, memPtrA );
736
737	memPtrA += bbs_memRead32( &ptrA->maxImageWidthE, memPtrA );
738	memPtrA += bbs_memRead32( &ptrA->maxImageHeightE, memPtrA );
739	memPtrA += bbs_memRead32( &ptrA->maxRadiusE, memPtrA );
740	memPtrA += bbs_memRead32( &ptrA->patchWidthE, memPtrA );
741	memPtrA += bbs_memRead32( &ptrA->patchHeightE, memPtrA );
742	memPtrA += bbs_memRead32( &ptrA->minScaleE, memPtrA );
743	memPtrA += bbs_memRead32( &ptrA->maxScaleE, memPtrA );
744	memPtrA += bbs_memRead32( &ptrA->scaleStepE, memPtrA );
745	memPtrA += bbs_memRead32( &ptrA->borderWidthE, memPtrA );
746	memPtrA += bbs_memRead32( &ptrA->borderHeightE, memPtrA );
747
748	if( memSizeL != bbf_Scanner_memSize( cpA, ptrA ) )
749	{
750		bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bbf_Scanner_memRead( struct bem_ScanGradientMove* ptrA, const uint16* memPtrA ):\n"
751			        "size mismatch" );
752		return 0;
753	}
754
755	if( bbs_Context_error( cpA ) ) return 0;
756
757	/* allocate arrays */
758	bbf_Scanner_alloc( cpA, ptrA, mtpA, FALSE );
759
760	if( bbs_Context_error( cpA ) ) return 0;
761
762	return memSizeL;
763}
764
765/* ------------------------------------------------------------------------- */
766
767/* ========================================================================= */
768/*                                                                           */
769/* ---- \ghd{ exec functions } --------------------------------------------- */
770/*                                                                           */
771/* ========================================================================= */
772
773/* ------------------------------------------------------------------------- */
774
775void bbf_Scanner_resetScan( struct bbs_Context* cpA, struct bbf_Scanner* ptrA )
776{
777	ptrA->xE = 0;
778	ptrA->yE = 0;
779	bbf_Scanner_initPatchBuffer( cpA, ptrA );
780}
781
782/* ------------------------------------------------------------------------- */
783
784void bbf_Scanner_assign( struct bbs_Context* cpA, struct bbf_Scanner* ptrA,
785					     const void* imagePtrA,
786						 uint32 imageWidthA,
787						 uint32 imageHeightA,
788						 const struct bts_Int16Rect* roiPtrA,
789						 const struct bbf_BitParam* paramPtrA )
790{
791	/* copy image */
792	bbf_Scanner_copyImage( cpA, ptrA, imagePtrA, imageWidthA, imageHeightA, roiPtrA );
793
794	ptrA->scaleE = ptrA->minScaleE;
795	bbf_BitParam_copy( cpA, &ptrA->bitParamE, paramPtrA );
796
797	/* compute effective max scale */
798	{
799		/* 16.16 */
800		uint32 maxHScaleL = ( ptrA->workWidthE << 16 ) / ( ptrA->patchWidthE + 1 );
801		uint32 maxVScaleL = ( ptrA->workHeightE << 16 ) / ( ptrA->patchHeightE + 1 );
802
803		/* 12.20 */
804		ptrA->effMaxScaleE = maxHScaleL < maxVScaleL ? ( maxHScaleL << 4 ) : ( maxVScaleL << 4 );
805
806		if( ptrA->maxScaleE > 0 ) ptrA->effMaxScaleE = ptrA->effMaxScaleE < ptrA->maxScaleE ? ptrA->effMaxScaleE : ptrA->maxScaleE;
807	}
808
809	ptrA->scaleExpE = 0;
810
811	/* downscale work image if necessary */
812	while( ptrA->scaleE > ( ( uint32 )( 2 << ptrA->scaleExpE ) << 20 ) ) bbf_Scanner_downscale( cpA, ptrA );
813
814	bbf_Scanner_createBitImage( cpA, ptrA );
815	bbf_Scanner_resetScan( cpA, ptrA );
816}
817
818/* ------------------------------------------------------------------------- */
819
820flag bbf_Scanner_nextScale( struct bbs_Context* cpA, struct bbf_Scanner* ptrA )
821{
822	if( ptrA->scaleE + bbf_Scanner_scalePrd( ptrA->scaleE, ptrA->scaleStepE ) >= ptrA->effMaxScaleE ) return FALSE;
823	ptrA->scaleE += bbf_Scanner_scalePrd( ptrA->scaleE, ptrA->scaleStepE );
824
825	/* downscale work image if necessary */
826	while( ptrA->scaleE > ( ( uint32 )( 2 << ptrA->scaleExpE ) << 20 ) ) bbf_Scanner_downscale( cpA, ptrA );
827
828	bbf_Scanner_createBitImage( cpA, ptrA );
829	bbf_Scanner_resetScan( cpA, ptrA );
830	return TRUE;
831}
832
833/* ------------------------------------------------------------------------- */
834
835const uint32* bbf_Scanner_getPatch( const struct bbf_Scanner* ptrA )
836{
837	return ptrA->patchBufferE.arrPtrE + ptrA->xE;
838}
839
840/* ------------------------------------------------------------------------- */
841
842flag bbf_Scanner_next( struct bbs_Context* cpA, struct bbf_Scanner* ptrA )
843{
844	if( ( ptrA->xE + 1 ) < ( int32 )( ptrA->currentWidthE - ptrA->patchWidthE ) )
845	{
846		ptrA->xE++;
847		return TRUE;
848	}
849
850	if( ( ptrA->yE + 1 ) >= ( int32 )( ptrA->currentHeightE - ptrA->patchHeightE ) ) return FALSE;
851
852	ptrA->xE = 0;
853	ptrA->yE++;
854
855	{
856		uint32 offL = ( ptrA->yE & 0x1F );
857		uint32 rowL = ( ptrA->yE >> 5 ) + ( offL > 0 ? 1 : 0 );
858
859		uint32 sizeL = ptrA->bitImageE.widthE;
860		uint32* dstL = ptrA->patchBufferE.arrPtrE;
861		uint32 iL;
862
863		if( rowL < ptrA->bitImageE.heightE )
864		{
865			uint32* srcL = ( uint32* )ptrA->bitImageE.arrE.arrPtrE + rowL * sizeL;
866			if( offL > 0 )
867			{
868				uint32 shlL = 32 - offL;
869				for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] = ( dstL[ iL ] >> 1 ) | ( srcL[ iL ] << shlL );
870			}
871			else
872			{
873				bbs_memcpy32( dstL, srcL, sizeL );
874			}
875		}
876		else
877		{
878			for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] >>= 1;
879		}
880	}
881
882	return TRUE;
883}
884
885/* ------------------------------------------------------------------------- */
886
887void bbf_Scanner_goToXY( struct bbs_Context* cpA, struct bbf_Scanner* ptrA, int32 xA, int32 yA )
888{
889	bbs_DEF_fNameL( "void bbf_Scanner_goToXY( struct bbs_Context* cpA, struct bbf_Scanner* ptrA, int32 xA, int32 yA )" )
890
891	if( xA > ( int32 )( ptrA->currentWidthE - ptrA->patchWidthE ) )
892	{
893		bbs_ERROR1( "%s:\nyA out of range", fNameL );
894		return;
895	}
896
897	ptrA->xE = xA;
898
899	if( ptrA->yE == yA ) return;
900
901	if( yA >= ( int32 )( ptrA->currentHeightE - ptrA->patchHeightE ) )
902	{
903		bbs_ERROR1( "%s:\nyA out of range", fNameL );
904		return;
905	}
906
907	if( yA == ptrA->yE + 1 )
908	{
909		uint32 offL, rowL;
910		uint32 sizeL;
911		uint32* dstL;
912		uint32 iL;
913
914		ptrA->yE = yA;
915		offL = ( ptrA->yE & 0x1F );
916		rowL = ( ptrA->yE >> 5 ) + ( offL > 0 ? 1 : 0 );
917
918		sizeL = ptrA->bitImageE.widthE;
919		dstL = ptrA->patchBufferE.arrPtrE;
920
921		if( rowL < ptrA->bitImageE.heightE )
922		{
923			uint32* srcL = ptrA->bitImageE.arrE.arrPtrE + rowL * sizeL;
924			if( offL > 0 )
925			{
926				uint32 shlL = 32 - offL;
927				for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] = ( dstL[ iL ] >> 1 ) | ( srcL[ iL ] << shlL );
928			}
929			else
930			{
931				bbs_memcpy32( dstL, srcL, sizeL );
932			}
933		}
934		else
935		{
936			for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] >>= 1;
937		}
938	}
939	else
940	{
941		uint32 offL, rowL;
942		uint32 sizeL;
943		uint32* dstL;
944		uint32 iL;
945
946		ptrA->yE = yA;
947		offL = ( ptrA->yE & 0x1F );
948		rowL = ( ptrA->yE >> 5 ) + ( offL > 0 ? 1 : 0 );
949
950		sizeL = ptrA->bitImageE.widthE;
951		dstL = ptrA->patchBufferE.arrPtrE;
952
953		if( rowL < ptrA->bitImageE.heightE )
954		{
955			if( offL > 0 )
956			{
957				uint32* src1L = ptrA->bitImageE.arrE.arrPtrE + rowL * sizeL;
958				uint32* src0L = src1L - sizeL;
959				uint32 shlL = 32 - offL;
960				for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] = ( src0L[ iL ] >> offL ) | ( src1L[ iL ] << shlL );
961			}
962			else
963			{
964				bbs_memcpy32( dstL, ptrA->bitImageE.arrE.arrPtrE + rowL * sizeL, sizeL );
965			}
966		}
967		else
968		{
969			uint32* srcL = ptrA->bitImageE.arrE.arrPtrE + ( rowL - 1 ) * sizeL;
970			for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] = srcL[ iL ] >> offL;
971		}
972	}
973}
974
975/* ------------------------------------------------------------------------- */
976
977void bbf_Scanner_goToIndex( struct bbs_Context* cpA, struct bbf_Scanner* ptrA, uint32 scanIndexA )
978{
979	int32 yL = scanIndexA / ptrA->currentWidthE;
980	int32 xL = scanIndexA - yL * ptrA->currentWidthE;
981	bbf_Scanner_goToXY( cpA, ptrA, xL, yL );
982}
983
984/* ------------------------------------------------------------------------- */
985
986void bbf_Scanner_goToUls( struct bbs_Context* cpA, struct bbf_Scanner* ptrA,
987						  int32 xA, int32 yA, uint32 scaleA )
988{
989	int32 xL = ( xA / ( int32 )( ptrA->scaleE >> 4 ) ) + ptrA->borderWidthE;
990	int32 yL = ( yA / ( int32 )( ptrA->scaleE >> 4 ) ) + ptrA->borderHeightE;
991
992	if( ptrA->scaleE != scaleA )
993	{
994		bbs_ERROR0( "bbf_Scanner_goToUls:\nScales no not match" );
995		return;
996	}
997
998	bbf_Scanner_goToXY( cpA, ptrA, xL, yL );
999}
1000
1001/* ------------------------------------------------------------------------- */
1002
1003/* resets output positions */
1004void bbf_Scanner_resetOutPos( struct bbs_Context* cpA, struct bbf_Scanner* ptrA )
1005{
1006	ptrA->outCountE = 0;
1007}
1008
1009/* ------------------------------------------------------------------------- */
1010
1011/* resets internal positions */
1012void bbf_Scanner_resetIntPos( struct bbs_Context* cpA, struct bbf_Scanner* ptrA )
1013{
1014	ptrA->intCountE = 0;
1015}
1016
1017/* ------------------------------------------------------------------------- */
1018
1019/* add internal position */
1020void bbf_Scanner_addIntPos( struct bbs_Context* cpA,
1021							struct bbf_Scanner* ptrA,
1022							uint32 idxA,
1023							int32 actA )
1024{
1025	if( ptrA->intCountE < ptrA->idxArrE.sizeE )
1026	{
1027        ptrA->idxArrE.arrPtrE[ ptrA->intCountE ] = idxA;
1028        ptrA->actArrE.arrPtrE[ ptrA->intCountE ] = actA;
1029		ptrA->intCountE++;
1030	}
1031	else
1032	{
1033		/* When buffer is full then replace lowest confidence-entry with new input
1034		 * This fallback solution causes soft degradation of performance when the buffer limit is reached.
1035		 */
1036		int32 minActL = 0x7FFFFFFF;
1037		uint32 minIdxL = 0;
1038		uint32 iL;
1039		int32* actArrL = ptrA->actArrE.arrPtrE;
1040		for( iL = 0; iL < ptrA->intCountE; iL++ )
1041		{
1042			if( actArrL[ iL ] < minActL )
1043			{
1044				minActL = actArrL[ iL ];
1045				minIdxL = iL;
1046			}
1047		}
1048
1049		if( actA > minActL )
1050		{
1051			ptrA->idxArrE.arrPtrE[ minIdxL ] = idxA;
1052			ptrA->actArrE.arrPtrE[ minIdxL ] = actA;
1053		}
1054	}
1055}
1056
1057/* ------------------------------------------------------------------------- */
1058
1059/* add external position */
1060void bbf_Scanner_addOutPos( struct bbs_Context* cpA,
1061							struct bbf_Scanner* ptrA,
1062							int32 xA,
1063							int32 yA,
1064							uint32 scaleA,
1065							int32 actA )
1066{
1067	if( ( ptrA->outCountE * 4 ) < ptrA->outArrE.sizeE )
1068	{
1069        ptrA->outArrE.arrPtrE[ ptrA->outCountE * 4 + 0 ] = xA;
1070        ptrA->outArrE.arrPtrE[ ptrA->outCountE * 4 + 1 ] = yA;
1071        ptrA->outArrE.arrPtrE[ ptrA->outCountE * 4 + 2 ] = scaleA;
1072        ptrA->outArrE.arrPtrE[ ptrA->outCountE * 4 + 3 ] = actA;
1073		ptrA->outCountE++;
1074	}
1075	else
1076	{
1077		/* When buffer is full then replace lowest confidence-entry with new input
1078		 * This fallback solution causes soft degradation of performance when the buffer limit is reached.
1079		 */
1080		int32 minActL = 0x7FFFFFFF;
1081		uint32 minIdxL = 0;
1082		uint32 iL;
1083		int32* outArrL = ptrA->outArrE.arrPtrE;
1084		for( iL = 0; iL < ptrA->outCountE; iL++ )
1085		{
1086			if( outArrL[ iL * 4 + 3 ] < minActL )
1087			{
1088				minActL = outArrL[ iL * 4 + 3 ];
1089				minIdxL = iL;
1090			}
1091		}
1092
1093		if( actA > minActL )
1094		{
1095			ptrA->idxArrE.arrPtrE[ minIdxL * 4 + 0 ] = xA;
1096			ptrA->idxArrE.arrPtrE[ minIdxL * 4 + 1 ] = yA;
1097			ptrA->idxArrE.arrPtrE[ minIdxL * 4 + 2 ] = scaleA;
1098			ptrA->idxArrE.arrPtrE[ minIdxL * 4 + 3 ] = actA;
1099		}
1100	}
1101}
1102
1103/* ------------------------------------------------------------------------- */
1104
1105/* remove overlaps */
1106uint32 bbf_Scanner_removeOutOverlaps( struct bbs_Context* cpA,
1107							          struct bbf_Scanner* ptrA,
1108									  uint32 overlapThrA )
1109{
1110	uint32 begIdxL = 0;				   /* begin index */
1111	uint32 endIdxL = ptrA->outCountE;  /* end index */
1112	uint32 iL;
1113	uint32 rw0L = ptrA->patchWidthE;
1114	uint32 rh0L = ptrA->patchHeightE;
1115	int32* outArrL = ptrA->outArrE.arrPtrE;
1116
1117	if( overlapThrA >= 0x010000 ) return ptrA->outCountE;
1118
1119	while( endIdxL - begIdxL > 1 )
1120	{
1121		int32 x1L, y1L, s1L, a1L;
1122		int32 r1wL, r1hL;
1123		uint32 r1aL;
1124
1125		/* find maximum activity */
1126		uint32 maxIdxL  = 0;
1127
1128		{
1129			int32 maxActL = ( int32 )0x80000000;
1130			for( iL = begIdxL; iL < endIdxL; iL++ )
1131			{
1132				if( outArrL[ iL * 4 + 3 ] > maxActL )
1133				{
1134					maxActL = outArrL[ iL * 4 + 3 ];
1135					maxIdxL = iL;
1136				}
1137			}
1138		}
1139
1140		/* swap with position 0 */
1141		x1L = outArrL[ maxIdxL * 4 + 0 ];
1142		y1L = outArrL[ maxIdxL * 4 + 1 ];
1143		s1L = outArrL[ maxIdxL * 4 + 2 ];
1144		a1L = outArrL[ maxIdxL * 4 + 3 ];
1145
1146		outArrL[ maxIdxL * 4 + 0 ] = outArrL[ begIdxL * 4 + 0 ];
1147		outArrL[ maxIdxL * 4 + 1 ] = outArrL[ begIdxL * 4 + 1 ];
1148		outArrL[ maxIdxL * 4 + 2 ] = outArrL[ begIdxL * 4 + 2 ];
1149		outArrL[ maxIdxL * 4 + 3 ] = outArrL[ begIdxL * 4 + 3 ];
1150
1151		outArrL[ begIdxL * 4 + 0 ] = x1L;
1152		outArrL[ begIdxL * 4 + 1 ] = y1L;
1153		outArrL[ begIdxL * 4 + 2 ] = s1L;
1154		outArrL[ begIdxL * 4 + 3 ] = a1L;
1155
1156		/* rectangle */
1157		r1wL = ( rw0L * ( s1L >> 12 ) + 128 ) >> 8;
1158		r1hL = ( rh0L * ( s1L >> 12 ) + 128 ) >> 8;
1159		r1aL = ( uint32 )r1wL * ( uint32 )r1hL;
1160
1161		/* remove coordinate fractions */
1162		x1L = ( x1L + ( 1 << 15 ) ) >> 16;
1163		y1L = ( y1L + ( 1 << 15 ) ) >> 16;
1164
1165		/* compare to other rectangles and remove overlaps */
1166		for( iL = endIdxL - 1; iL > begIdxL; iL-- )
1167		{
1168			int32* x2pL = &outArrL[ iL * 4 + 0 ];
1169			int32* y2pL = &outArrL[ iL * 4 + 1 ];
1170			int32* s2pL = &outArrL[ iL * 4 + 2 ];
1171			int32* a2pL = &outArrL[ iL * 4 + 3 ];
1172
1173			int32 x2L = ( *x2pL + ( 1 << 15 ) ) >> 16;
1174			int32 y2L = ( *y2pL + ( 1 << 15 ) ) >> 16;
1175
1176			/* rectangle */
1177			int32 r2wL = ( rw0L * ( *s2pL >> 12 ) + 128 ) >> 8;
1178			int32 r2hL = ( rh0L * ( *s2pL >> 12 ) + 128 ) >> 8;
1179			uint32 r2aL = r2wL * r2hL;
1180
1181			/* intersection */
1182			int32 rx1L = x1L > x2L ? x1L : x2L;
1183			int32 rx2L = ( x1L + r1wL ) < ( x2L + r2wL ) ? ( x1L + r1wL ) : ( x2L + r2wL );
1184			int32 ry1L = y1L > y2L ? y1L : y2L;
1185			int32 ry2L = ( y1L + r1hL ) < ( y2L + r2hL ) ? ( y1L + r1hL ) : ( y2L + r2hL );
1186			uint32 riwL;
1187
1188			rx2L = ( rx2L > rx1L ) ? rx2L : rx1L;
1189			ry2L = ( ry2L > ry1L ) ? ry2L : ry1L;
1190			riwL = ( uint32 )( rx2L - rx1L ) * ( uint32 )( ry2L - ry1L );
1191
1192			if( riwL > ( ( ( overlapThrA >> 8 ) * ( r1aL < r2aL ? r1aL : r2aL ) ) >> 8 ) )
1193			{
1194				endIdxL--;
1195				*x2pL = outArrL[ endIdxL * 4 + 0 ];
1196				*y2pL = outArrL[ endIdxL * 4 + 1 ];
1197				*s2pL = outArrL[ endIdxL * 4 + 2 ];
1198				*a2pL = outArrL[ endIdxL * 4 + 3 ];
1199			}
1200		}
1201
1202		begIdxL++;
1203	}
1204
1205	ptrA->outCountE = endIdxL;
1206
1207	return endIdxL;
1208}
1209
1210/* ------------------------------------------------------------------------- */
1211
1212/* remove internal overlaps */
1213uint32 bbf_Scanner_removeIntOverlaps( struct bbs_Context* cpA,
1214								      struct bbf_Scanner* ptrA,
1215									  uint32 overlapThrA )
1216{
1217    uint32 begIdxL = 0;		 /* begin index */
1218    uint32 endIdxL = ptrA->intCountE;  /* end index */
1219	uint32 iL;
1220	uint32 rw0L   = ptrA->patchWidthE;
1221	uint32 rh0L   = ptrA->patchHeightE;
1222	int32 minAreaL = ( overlapThrA * rw0L * rh0L ) >> 16;
1223
1224	int32*  actArrL = ptrA->actArrE.arrPtrE;
1225	uint32* idxArrL = ptrA->idxArrE.arrPtrE;
1226
1227	if( overlapThrA >= 0x010000 ) return ptrA->intCountE;
1228
1229	while( endIdxL - begIdxL > 1 )
1230	{
1231		/* find maximum activity */
1232		int32 a1L = ( int32 )0x80000000;
1233		uint32 i1L = 0;
1234		uint32 maxIdxL  = 0;
1235		int32 x1L, y1L;
1236
1237		for( iL = begIdxL; iL < endIdxL; iL++ )
1238		{
1239            if( actArrL[ iL ] > a1L )
1240			{
1241				a1L = actArrL[ iL ];
1242				maxIdxL = iL;
1243			}
1244		}
1245
1246		/* swap with position 0 */
1247		i1L = idxArrL[ maxIdxL ];
1248		idxArrL[ maxIdxL ] = idxArrL[ begIdxL ];
1249		actArrL[ maxIdxL ] = actArrL[ begIdxL ];
1250		idxArrL[ begIdxL ] = i1L;
1251		actArrL[ begIdxL ] = a1L;
1252
1253		/* upper left coordinates */
1254		y1L = i1L / ptrA->currentWidthE;
1255		x1L = i1L - ( y1L * ptrA->currentWidthE );
1256
1257		/* compare to other rectangles and remove overlaps */
1258		for( iL = endIdxL - 1; iL > begIdxL; iL-- )
1259		{
1260			int32*  a2pL = &actArrL[ iL ];
1261			uint32* i2pL = &idxArrL[ iL ];
1262
1263			int32 y2L = *i2pL / ptrA->currentWidthE;
1264			int32 x2L = *i2pL - ( y2L * ptrA->currentWidthE );
1265
1266			int32 dxL = rw0L - ( x1L > x2L ? x1L - x2L : x2L - x1L );
1267			int32 dyL = rh0L - ( y1L > y2L ? y1L - y2L : y2L - y1L );
1268
1269			dxL = dxL > 0 ? dxL : 0;
1270			dyL = dyL > 0 ? dyL : 0;
1271
1272			if( dxL * dyL > minAreaL )
1273			{
1274				endIdxL--;
1275				*a2pL = actArrL[ endIdxL ];
1276				*i2pL = idxArrL[ endIdxL ];
1277			}
1278		}
1279
1280		begIdxL++;
1281	}
1282
1283	ptrA->intCountE = endIdxL;
1284
1285	return ptrA->intCountE;
1286}
1287
1288/* ------------------------------------------------------------------------- */
1289
1290/* ========================================================================= */
1291