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/LocalScanner.h"
22
23/* ------------------------------------------------------------------------- */
24
25/* ========================================================================= */
26/*                                                                           */
27/* ---- \ghd{ auxiliary functions } ---------------------------------------- */
28/*                                                                           */
29/* ========================================================================= */
30
31/* ------------------------------------------------------------------------- */
32
33/** allocates arays */
34void bbf_LocalScanner_alloc( struct bbs_Context* cpA,
35							 struct bbf_LocalScanner* ptrA,
36							 struct bbs_MemTbl* mtpA )
37{
38	struct bbs_MemTbl memTblL = *mtpA;
39	struct bbs_MemSeg* espL = bbs_MemTbl_segPtr( cpA, &memTblL, 0 );
40	struct bbs_MemSeg* sspL = bbs_MemTbl_sharedSegPtr( cpA, &memTblL, 0 );
41
42	/* filter patch dimension */
43	uint32 proL = ptrA->maxRadiusE;
44	uint32 pwoL = ( proL << 1 ) + 1;
45
46	/* output image size (bit image) */
47	uint32 woL = ptrA->maxImageWidthE;
48	uint32 hoL = ptrA->maxImageHeightE;
49
50	if( ptrA->minScaleExpE > 0 )
51	{
52		/* allocate working image */
53		bbs_UInt8Arr_create( cpA, &ptrA->workImageBufferE, ( woL >> 1 ) * ( hoL >> 1 ), espL );
54		bbs_UInt8Arr_fill( cpA, &ptrA->workImageBufferE, 0 );
55	}
56
57	/* allocate bit image */
58	bim_UInt32Image_create( cpA, &ptrA->bitImageE, woL, ( hoL >> 5 ) + ( ( ( hoL & 0x1F ) != 0 ) ? 1 : 0 ), espL );
59	bim_UInt32Image_setAllPixels( cpA, &ptrA->bitImageE, 0, 0 );
60
61	/* allocate patch buffer */
62	bbs_UInt32Arr_create( cpA, &ptrA->patchBufferE, ptrA->bitImageE.widthE, espL );
63	bbs_UInt32Arr_fill( cpA, &ptrA->patchBufferE, 0 );
64
65	/* allocate table */
66	bim_UInt32Image_create( cpA, &ptrA->satE, woL + pwoL, pwoL + 1, sspL );
67}
68
69/* ------------------------------------------------------------------------- */
70
71/** downscales original image by factor 2 */
72void bbf_LocalScanner_downscale0( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
73{
74	int32 w0L = ptrA->origWidthE;
75	int32 h0L = ptrA->origHeightE;
76
77	int32 w1L = ( w0L - ptrA->xOffE ) >> 1;
78	int32 h1L = ( h0L - ptrA->yOffE ) >> 1;
79
80	const uint8* iArrL = ptrA->origImagePtrE + ptrA->xOffE + ptrA->yOffE * w0L;
81		  uint8* oArrL = ptrA->workImageBufferE.arrPtrE;
82
83	int32 iL, jL;
84	int32 kL = 0;
85
86	bbs_UInt8Arr_size( cpA, &ptrA->workImageBufferE, w1L * h1L );
87	ptrA->workImagePtrE = ptrA->workImageBufferE.arrPtrE;
88	ptrA->workWidthE = w1L;
89	ptrA->workHeightE = h1L;
90
91	for( jL = 0; jL < h1L; jL++ )
92	{
93		for( iL = 0; iL < w1L; iL++ )
94		{
95			int32 idxL = jL * 2 * w0L + iL * 2;
96			oArrL[ kL++ ] = ( ( uint32 )iArrL[ idxL           ] +
97										iArrL[ idxL + 1       ] +
98										iArrL[ idxL + w0L     ] +
99										iArrL[ idxL + w0L + 1 ] + 2 ) >> 2;
100		}
101	}
102}
103
104/* ------------------------------------------------------------------------- */
105
106/** downscales work image by factor 2 */
107void bbf_LocalScanner_downscale1( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
108{
109	int32 w0L = ptrA->workWidthE;
110	int32 h0L = ptrA->workHeightE;
111	int32 w1L = w0L >> 1;
112	int32 h1L = h0L >> 1;
113
114    uint8* arrL = ptrA->workImageBufferE.arrPtrE;
115
116	int32 iL, jL;
117	int32 kL = 0;
118
119	for( jL = 0; jL < h1L; jL++ )
120	{
121		for( iL = 0; iL < w1L; iL++ )
122		{
123			int32 idxL = jL * 2 * w0L + iL * 2;
124			arrL[ kL++ ] = ( ( uint32 )arrL[ idxL ] +
125									   arrL[ idxL + 1 ] +
126									   arrL[ idxL + w0L ] +
127									   arrL[ idxL + w0L + 1 ] + 2 ) >> 2;
128		}
129	}
130
131	ptrA->workWidthE = w1L;
132	ptrA->workHeightE = h1L;
133}
134
135/* ------------------------------------------------------------------------- */
136
137/** downscales by factor 2 */
138void bbf_LocalScanner_downscale( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
139{
140	uint32 iL;
141	if( ptrA->scaleExpE > 0 ) bbf_LocalScanner_downscale0( cpA, ptrA );
142	for( iL = 1; iL < ptrA->scaleExpE; iL++ ) bbf_LocalScanner_downscale1( cpA, ptrA );
143}
144
145/* ------------------------------------------------------------------------- */
146
147/** computes bit image */
148void bbf_LocalScanner_createBitImage( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
149{
150	bbs_DEF_fNameL( "void bbf_LocalScanner_createBitImage( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )" )
151
152	uint32 iL, jL;
153
154	uint32 proL = ptrA->bitParamE.outerRadiusE;
155	uint32 priL = ptrA->bitParamE.innerRadiusE;
156	uint32 pwoL = ( proL << 1 ) + 1;
157	uint32 pwiL = ( priL << 1 ) + 1;
158
159	/* areas of inner and outer rectangles */
160	uint32 poAreaL = pwoL * pwoL;
161	uint32 piAreaL = pwiL * pwiL;
162
163	uint32 wL, hL; /* input image size */
164
165	uint32 wsL, hsL;
166	uint32* satL;
167	uint32 satSizeL;
168	uint32 swi1L = 0; /* writing index */
169	uint32 swi2L = 0; /* writing index */
170	uint32 sriL = 0;  /* reading index */
171	uint32 siL[ 8 ];
172
173	uint32  bitMaskL;
174	uint32* bitRowL;
175
176
177	if( proL <= priL )
178	{
179		bbs_ERROR1( "%s:\n outer radius <= inner radius", fNameL );
180		return;
181	}
182
183	/* input image size */
184	wL = ptrA->workWidthE;
185	hL = ptrA->workHeightE;
186
187	if( wL <= pwoL || hL <= pwoL )
188	{
189		bbs_ERROR1( "%s:\n image is too small", fNameL );
190		return;
191	}
192
193	ptrA->currentWidthE  = wL;
194	ptrA->currentHeightE = hL;
195
196	/* reset scan region */
197	ptrA->workScanRegionE = bts_Int16Rect_create( 0, 0, ptrA->currentWidthE, ptrA->currentHeightE );
198
199	/* initialize bit image */
200	bim_UInt32Image_size( cpA, &ptrA->bitImageE, wL, ( hL >> 5 ) + ( ( ( hL & 0x1F ) != 0 ) ? 1 : 0 ) );
201	bim_UInt32Image_setAllPixels( cpA, &ptrA->bitImageE, 0, 0 );
202
203	bitMaskL = 1;
204	bitRowL = ( uint32* )ptrA->bitImageE.arrE.arrPtrE;
205
206	/* width of table */
207	wsL = wL + pwoL;
208
209	/* height of table */
210	hsL = pwoL + 1;
211
212	bim_UInt32Image_size( cpA, &ptrA->satE, wsL, hsL );
213
214	satL = ( uint32* )ptrA->satE.arrE.arrPtrE;
215	satSizeL = ptrA->satE.arrE.sizeE;
216
217	/* compute table and bit image */
218	for( iL = wsL * ( proL + 1 ); iL > 0; iL-- ) satL[ swi1L++ ] = 0;
219	swi2L = swi1L - wsL;
220
221	for( jL = 0; jL < hL + proL; jL++ )
222	{
223		if( jL < hL ) /* rescale area */
224		{
225			const uint8* arr0L = &ptrA->workImagePtrE[ jL * wL ];
226			uint32 hSumL = 0;
227			for( iL = 0; iL <= proL; iL++ ) satL[ swi1L++ ] = 0;
228			swi2L += iL;
229			for( iL = 0; iL < wL; iL++ )   satL[ swi1L++ ] = ( hSumL += arr0L[ iL ] ) + satL[ swi2L++ ];
230			for( iL = 0; iL < proL; iL++ ) satL[ swi1L++ ] =   hSumL                  + satL[ swi2L++ ];
231		}
232		else /* image is processed - fill in 0s */
233		{
234			for( iL = 0; iL < wsL; iL++ ) satL[ swi1L++ ] = satL[ swi2L++ ];
235		}
236
237		swi1L = ( swi1L < satSizeL ) ? swi1L : 0;
238		swi2L = ( swi2L < satSizeL ) ? swi2L : 0;
239
240		/* fill line in bit image */
241		if( jL >= proL )
242		{
243			const uint32* rSatL = satL;
244
245			/* table coordinate indices for outer rectangle */
246			siL[ 0 ] = sriL;
247			siL[ 1 ] = siL[ 0 ] + pwoL;
248			siL[ 2 ] = siL[ 0 ] + pwoL * wsL;
249			siL[ 2 ] -= ( siL[ 2 ] >= satSizeL ) ? satSizeL : 0;
250			siL[ 3 ] = siL[ 2 ] + pwoL;
251
252			/* table coordinate indices for inner rectangle */
253			siL[ 4 ] = siL[ 0 ] + ( proL - priL ) * wsL + ( proL - priL );
254			siL[ 4 ] -= ( siL[ 4 ] >= satSizeL ) ? satSizeL : 0;
255			siL[ 5 ] = siL[ 4 ] + pwiL;
256			siL[ 6 ] = siL[ 4 ] + pwiL * wsL;
257			siL[ 6 ] -= ( siL[ 6 ] >= satSizeL ) ? satSizeL : 0;
258			siL[ 7 ] = siL[ 6 ] + pwiL;
259			sriL += wsL;
260			if( sriL == satSizeL ) sriL = 0;
261
262			for( iL = 0; iL < wL; iL++ )
263			{
264				uint32 oAvgL = ( rSatL[ siL[ 0 ] ] - rSatL[ siL[ 1 ] ] - rSatL[ siL[ 2 ] ] + rSatL[ siL[ 3 ] ] ) * piAreaL;
265				uint32 iAvgL = ( rSatL[ siL[ 4 ] ] - rSatL[ siL[ 5 ] ] - rSatL[ siL[ 6 ] ] + rSatL[ siL[ 7 ] ] ) * poAreaL;
266				bitRowL[ iL ] |= ( iAvgL > oAvgL ) ? bitMaskL : 0;
267				rSatL++;
268			}
269			if( ( bitMaskL <<= 1 ) == 0 )
270			{
271				bitRowL += wL;
272				bitMaskL = 1;
273			}
274		}
275	}
276}
277
278/* -------------------------------------------------------------------------- */
279
280/** inilialize patch buffer */
281void bbf_LocalScanner_initPatchBuffer( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
282{
283	int32 ybL = ptrA->workScanRegionE.y1E >> 5;
284	int32 yoL = ptrA->workScanRegionE.y1E & 0x1F;
285	int32 xbL = ptrA->workScanRegionE.x1E;
286	uint32 wsrWidthL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E;
287
288	bbs_UInt32Arr_size( cpA, &ptrA->patchBufferE, ptrA->bitImageE.widthE );
289
290	if( yoL == 0 )
291	{
292		bbs_memcpy32( ptrA->patchBufferE.arrPtrE + xbL,
293			          ptrA->bitImageE.arrE.arrPtrE + ybL * ptrA->bitImageE.widthE + xbL,
294					  wsrWidthL );
295	}
296	else if( ybL == ( int32 )ptrA->bitImageE.heightE - 1 )
297	{
298		uint32* dstL = ptrA->patchBufferE.arrPtrE + xbL;
299		const uint32* srcL = ptrA->bitImageE.arrE.arrPtrE + ybL * ptrA->bitImageE.widthE + xbL;
300		uint32 iL;
301		for( iL = 0; iL < wsrWidthL; iL++ ) dstL[ iL ] = srcL[ iL ] >> yoL;
302	}
303	else
304	{
305		uint32* dstL = ptrA->patchBufferE.arrPtrE + xbL;
306		const uint32* src0L = ptrA->bitImageE.arrE.arrPtrE + ybL * ptrA->bitImageE.widthE + xbL;
307		const uint32* src1L = src0L + ptrA->bitImageE.widthE;
308		uint32 iL;
309		uint32 slL = 32 - yoL;
310		for( iL = 0; iL < wsrWidthL; iL++ ) dstL[ iL ] = ( src0L[ iL ] >> yoL ) | ( src1L[ iL ] << slL );
311	}
312}
313
314/* ------------------------------------------------------------------------- */
315
316/* sets work scan region from original scan region according to scale exponent */
317void bbf_LocalScanner_setWorkScanRegion( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
318{
319	int32 xMinL = ptrA->origScanRegionE.x1E >> ptrA->scaleExpE;
320	int32 yMinL = ptrA->origScanRegionE.y1E >> ptrA->scaleExpE;
321	int32 xMaxL = ptrA->origScanRegionE.x2E >> ptrA->scaleExpE;
322	int32 yMaxL = ptrA->origScanRegionE.y2E >> ptrA->scaleExpE;
323	ptrA->workScanRegionE.x1E = ( xMinL < 0 ) ? 0 : xMinL;
324	ptrA->workScanRegionE.y1E = ( yMinL < 0 ) ? 0 : yMinL;
325	ptrA->workScanRegionE.x2E = ( xMaxL > ( int32 )ptrA->currentWidthE ) ? ptrA->currentWidthE : xMaxL;
326	ptrA->workScanRegionE.y2E = ( yMaxL > ( int32 )ptrA->currentHeightE ) ? ptrA->currentHeightE : yMaxL;
327}
328
329/* ------------------------------------------------------------------------- */
330
331/* ========================================================================= */
332/*                                                                           */
333/* ---- \ghd{ constructor / destructor } ----------------------------------- */
334/*                                                                           */
335/* ========================================================================= */
336
337/* ------------------------------------------------------------------------- */
338
339void bbf_LocalScanner_init( struct bbs_Context* cpA,
340					        struct bbf_LocalScanner* ptrA )
341{
342	ptrA->xE = 0;
343	ptrA->yE = 0;
344	ptrA->xOffE = 0;
345	ptrA->yOffE = 0;
346	ptrA->currentWidthE = 0;
347	ptrA->currentHeightE = 0;
348	ptrA->workWidthE = 0;
349	ptrA->workHeightE = 0;
350	ptrA->workImagePtrE = NULL;
351	ptrA->origWidthE = 0;
352	ptrA->origHeightE = 0;
353	ptrA->origImagePtrE = NULL;
354	bbf_BitParam_init( cpA, &ptrA->bitParamE );
355	bbs_UInt8Arr_init( cpA, &ptrA->workImageBufferE );
356	bim_UInt32Image_init( cpA, &ptrA->satE );
357	bim_UInt32Image_init( cpA, &ptrA->bitImageE );
358	bbs_UInt32Arr_init( cpA, &ptrA->patchBufferE );
359	bts_Int16Rect_init( cpA, &ptrA->origScanRegionE );
360	bts_Int16Rect_init( cpA, &ptrA->workScanRegionE );
361
362	ptrA->patchWidthE = 0;
363	ptrA->patchHeightE = 0;
364	ptrA->scaleExpE = 0;
365	ptrA->maxImageWidthE = 0;
366	ptrA->maxImageHeightE = 0;
367	ptrA->minScaleExpE = 0;
368	ptrA->maxRadiusE = 0;
369}
370
371/* ------------------------------------------------------------------------- */
372
373void bbf_LocalScanner_exit( struct bbs_Context* cpA,
374				            struct bbf_LocalScanner* ptrA )
375{
376	ptrA->xE = 0;
377	ptrA->yE = 0;
378	ptrA->xOffE = 0;
379	ptrA->yOffE = 0;
380	ptrA->currentWidthE = 0;
381	ptrA->currentHeightE = 0;
382	ptrA->workWidthE = 0;
383	ptrA->workHeightE = 0;
384	ptrA->workImagePtrE = NULL;
385	ptrA->origWidthE = 0;
386	ptrA->origHeightE = 0;
387	ptrA->origImagePtrE = NULL;
388	bbf_BitParam_exit( cpA, &ptrA->bitParamE );
389	bbs_UInt8Arr_exit( cpA, &ptrA->workImageBufferE );
390	bim_UInt32Image_exit( cpA, &ptrA->satE );
391	bim_UInt32Image_exit( cpA, &ptrA->bitImageE );
392	bbs_UInt32Arr_exit( cpA, &ptrA->patchBufferE );
393	bts_Int16Rect_exit( cpA, &ptrA->origScanRegionE );
394	bts_Int16Rect_exit( cpA, &ptrA->workScanRegionE );
395
396	ptrA->patchWidthE = 0;
397	ptrA->patchHeightE = 0;
398	ptrA->scaleExpE = 0;
399	ptrA->maxImageWidthE = 0;
400	ptrA->maxImageHeightE = 0;
401	ptrA->minScaleExpE = 0;
402	ptrA->maxRadiusE = 0;
403}
404
405/* ------------------------------------------------------------------------- */
406
407/* ========================================================================= */
408/*                                                                           */
409/* ---- \ghd{ operators } -------------------------------------------------- */
410/*                                                                           */
411/* ========================================================================= */
412
413/* ------------------------------------------------------------------------- */
414
415void bbf_LocalScanner_copy( struct bbs_Context* cpA,
416				            struct bbf_LocalScanner* ptrA,
417					        const struct bbf_LocalScanner* srcPtrA )
418{
419	bbs_ERROR0( "bbf_LocalScanner_copy:\n Function is not available" );
420}
421
422/* ------------------------------------------------------------------------- */
423
424flag bbf_LocalScanner_equal( struct bbs_Context* cpA,
425							 const struct bbf_LocalScanner* ptrA,
426							 const struct bbf_LocalScanner* srcPtrA )
427{
428	bbs_ERROR0( "bbf_LocalScanner_equal:\n Function is not available" );
429	return FALSE;
430}
431
432/* ------------------------------------------------------------------------- */
433
434/* ========================================================================= */
435/*                                                                           */
436/* ---- \ghd{ query functions } -------------------------------------------- */
437/*                                                                           */
438/* ========================================================================= */
439
440/* ------------------------------------------------------------------------- */
441
442uint32 bbf_LocalScanner_positions( const struct bbf_LocalScanner* ptrA )
443{
444	int32 wL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E - ptrA->patchWidthE;
445	int32 hL = ptrA->workScanRegionE.y2E - ptrA->workScanRegionE.y1E - ptrA->patchHeightE;
446	return ( ( wL < 0 ) ? 0 : wL ) * ( ( hL < 0 ) ? 0 : hL );
447}
448
449/* ------------------------------------------------------------------------- */
450
451uint32 bbf_LocalScanner_scanIndex( const struct bbf_LocalScanner* ptrA )
452{
453	int32 wL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E - ptrA->patchWidthE;
454	return ( ptrA->yE - ptrA->workScanRegionE.y1E ) * wL + ( ptrA->xE - ptrA->workScanRegionE.x1E );
455}
456
457/* ------------------------------------------------------------------------- */
458
459void bbf_LocalScanner_pos( const struct bbf_LocalScanner* ptrA, int32* xPtrA, int32* yPtrA )
460{
461	*xPtrA = ( ( ptrA->xE << ptrA->scaleExpE ) + ptrA->xOffE ) << 16;
462	*yPtrA = ( ( ptrA->yE << ptrA->scaleExpE ) + ptrA->yOffE ) << 16;
463}
464
465/* ------------------------------------------------------------------------- */
466
467void bbf_LocalScanner_idxPos( const struct bbf_LocalScanner* ptrA, uint32 scanIndexA, int32* xPtrA, int32* yPtrA )
468{
469	uint32 wL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E - ptrA->patchWidthE;
470	int32 xL = ( scanIndexA % wL ) + ptrA->workScanRegionE.x1E;
471	int32 yL = ( scanIndexA / wL ) + ptrA->workScanRegionE.y1E;
472	*xPtrA = ( ( xL << ptrA->scaleExpE ) + ptrA->xOffE ) << 16;
473	*yPtrA = ( ( yL << ptrA->scaleExpE ) + ptrA->yOffE ) << 16;
474}
475
476/* ------------------------------------------------------------------------- */
477
478/* ========================================================================= */
479/*                                                                           */
480/* ---- \ghd{ modify functions } ------------------------------------------- */
481/*                                                                           */
482/* ========================================================================= */
483
484/* ------------------------------------------------------------------------- */
485
486void bbf_LocalScanner_create( struct bbs_Context* cpA,
487							  struct bbf_LocalScanner* ptrA,
488							  uint32 patchWidthA,
489							  uint32 patchHeightA,
490							  uint32 scaleExpA,
491							  uint32 maxImageWidthA,
492							  uint32 maxImageHeightA,
493							  uint32 minScaleExpA,
494							  uint32 maxRadiusA,
495							  struct bbs_MemTbl* mtpA )
496{
497	ptrA->patchWidthE = patchWidthA;
498	ptrA->patchHeightE = patchHeightA;
499	ptrA->scaleExpE = scaleExpA;
500	ptrA->maxImageWidthE = maxImageWidthA;
501	ptrA->maxImageHeightE = maxImageHeightA;
502	ptrA->minScaleExpE = minScaleExpA;
503	ptrA->maxRadiusE = maxRadiusA;
504	bbf_LocalScanner_alloc( cpA, ptrA, mtpA );
505}
506
507/* ------------------------------------------------------------------------- */
508
509void bbf_LocalScanner_bitParam( struct bbs_Context* cpA,
510							    struct bbf_LocalScanner* ptrA,
511								const struct bbf_BitParam* bitParamPtrA )
512{
513	if( !bbf_BitParam_equal( cpA, &ptrA->bitParamE, bitParamPtrA ) )
514	{
515		bbf_BitParam_copy( cpA, &ptrA->bitParamE, bitParamPtrA );
516		bbf_LocalScanner_createBitImage( cpA, ptrA );
517	}
518
519	bbf_LocalScanner_resetScan( cpA, ptrA );
520}
521
522/* ------------------------------------------------------------------------- */
523
524void bbf_LocalScanner_origScanRegion( struct bbs_Context* cpA,
525									  struct bbf_LocalScanner* ptrA,
526									  const struct bts_Int16Rect* scanRegionPtrA )
527{
528	ptrA->origScanRegionE = *scanRegionPtrA;
529	bbf_LocalScanner_setWorkScanRegion( cpA, ptrA );
530	bbf_LocalScanner_resetScan( cpA, ptrA );
531}
532
533/* ------------------------------------------------------------------------- */
534
535/* ========================================================================= */
536/*                                                                           */
537/* ---- \ghd{ I/O } -------------------------------------------------------- */
538/*                                                                           */
539/* ========================================================================= */
540
541/* ------------------------------------------------------------------------- */
542
543uint32 bbf_LocalScanner_memSize( struct bbs_Context* cpA,
544								 const struct bbf_LocalScanner* ptrA )
545{
546	uint32 memSizeL = bbs_SIZEOF16( uint32 ) +
547					  bbs_SIZEOF16( uint32 ); /* version */
548
549	memSizeL += bbs_SIZEOF16( ptrA->patchWidthE );
550	memSizeL += bbs_SIZEOF16( ptrA->patchHeightE );
551	memSizeL += bbs_SIZEOF16( ptrA->scaleExpE );
552	memSizeL += bbs_SIZEOF16( ptrA->maxImageWidthE );
553	memSizeL += bbs_SIZEOF16( ptrA->maxImageHeightE );
554	memSizeL += bbs_SIZEOF16( ptrA->minScaleExpE );
555	memSizeL += bbs_SIZEOF16( ptrA->maxRadiusE );
556
557	return memSizeL;
558}
559
560/* ------------------------------------------------------------------------- */
561
562uint32 bbf_LocalScanner_memWrite( struct bbs_Context* cpA,
563						     const struct bbf_LocalScanner* ptrA,
564						     uint16* memPtrA )
565{
566	uint32 memSizeL = bbf_LocalScanner_memSize( cpA, ptrA );
567	memPtrA += bbs_memWrite32( &memSizeL, memPtrA );
568	memPtrA += bbs_memWriteUInt32( bbf_LOCAL_SCANNER_VERSION, memPtrA );
569
570	memPtrA += bbs_memWrite32( &ptrA->patchWidthE, memPtrA );
571	memPtrA += bbs_memWrite32( &ptrA->patchHeightE, memPtrA );
572	memPtrA += bbs_memWrite32( &ptrA->scaleExpE, memPtrA );
573	memPtrA += bbs_memWrite32( &ptrA->maxImageWidthE, memPtrA );
574	memPtrA += bbs_memWrite32( &ptrA->maxImageHeightE, memPtrA );
575	memPtrA += bbs_memWrite32( &ptrA->minScaleExpE, memPtrA );
576	memPtrA += bbs_memWrite32( &ptrA->maxRadiusE, memPtrA );
577	return memSizeL;
578}
579
580/* ------------------------------------------------------------------------- */
581
582uint32 bbf_LocalScanner_memRead( struct bbs_Context* cpA,
583						    struct bbf_LocalScanner* ptrA,
584						    const uint16* memPtrA,
585						    struct bbs_MemTbl* mtpA )
586{
587	uint32 memSizeL, versionL;
588
589	if( bbs_Context_error( cpA ) ) return 0;
590	memPtrA += bbs_memRead32( &memSizeL, memPtrA );
591	memPtrA += bbs_memReadVersion32( cpA, &versionL, bbf_LOCAL_SCANNER_VERSION, memPtrA );
592
593	memPtrA += bbs_memRead32( &ptrA->patchWidthE, memPtrA );
594	memPtrA += bbs_memRead32( &ptrA->patchHeightE, memPtrA );
595	memPtrA += bbs_memRead32( &ptrA->scaleExpE, memPtrA );
596	memPtrA += bbs_memRead32( &ptrA->maxImageWidthE, memPtrA );
597	memPtrA += bbs_memRead32( &ptrA->maxImageHeightE, memPtrA );
598	memPtrA += bbs_memRead32( &ptrA->minScaleExpE, memPtrA );
599	memPtrA += bbs_memRead32( &ptrA->maxRadiusE, memPtrA );
600
601	if( memSizeL != bbf_LocalScanner_memSize( cpA, ptrA ) )
602	{
603		bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bbf_LocalScanner_memRead( struct bem_ScanGradientMove* ptrA, const uint16* memPtrA ):\n"
604			        "size mismatch" );
605		return 0;
606	}
607
608	if( bbs_Context_error( cpA ) ) return 0;
609
610	/* allocate arrays */
611	bbf_LocalScanner_alloc( cpA, ptrA, mtpA );
612
613	if( bbs_Context_error( cpA ) ) return 0;
614
615	return memSizeL;
616}
617
618/* ------------------------------------------------------------------------- */
619
620/* ========================================================================= */
621/*                                                                           */
622/* ---- \ghd{ exec functions } --------------------------------------------- */
623/*                                                                           */
624/* ========================================================================= */
625
626/* ------------------------------------------------------------------------- */
627
628void bbf_LocalScanner_resetScan( struct bbs_Context* cpA,
629								 struct bbf_LocalScanner* ptrA )
630{
631	ptrA->xE = ptrA->workScanRegionE.x1E;
632	ptrA->yE = ptrA->workScanRegionE.y1E;
633	bbf_LocalScanner_initPatchBuffer( cpA, ptrA );
634}
635
636/* ------------------------------------------------------------------------- */
637
638void bbf_LocalScanner_assign( struct bbs_Context* cpA,
639							  struct bbf_LocalScanner* ptrA,
640							  const uint8* imagePtrA,
641							  uint32 imageWidthA,
642							  uint32 imageHeightA,
643							  const struct bbf_BitParam* paramPtrA )
644{
645	if( ptrA->scaleExpE == 0 )
646	{
647		ptrA->workImagePtrE = imagePtrA;
648		ptrA->workWidthE = imageWidthA;
649		ptrA->workHeightE = imageHeightA;
650	}
651	else
652	{
653		ptrA->origImagePtrE = imagePtrA;
654		ptrA->origWidthE = imageWidthA;
655		ptrA->origHeightE = imageHeightA;
656	}
657
658	ptrA->bitParamE = *paramPtrA;
659	ptrA->xOffE = 0;
660	ptrA->yOffE = 0;
661	ptrA->origScanRegionE = bts_Int16Rect_create( 0, 0, imageWidthA, imageHeightA );
662	bbf_LocalScanner_downscale( cpA, ptrA );
663	bbf_LocalScanner_createBitImage( cpA, ptrA );
664	bbf_LocalScanner_resetScan( cpA, ptrA );
665}
666
667/* ------------------------------------------------------------------------- */
668
669const uint32* bbf_LocalScanner_getPatch( const struct bbf_LocalScanner* ptrA )
670{
671	return ptrA->patchBufferE.arrPtrE + ptrA->xE;
672}
673
674/* ------------------------------------------------------------------------- */
675
676flag bbf_LocalScanner_next( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
677{
678	if( ( ptrA->xE + 1 ) < ptrA->workScanRegionE.x2E - ( int32 )ptrA->patchWidthE )
679	{
680		ptrA->xE++;
681		return TRUE;
682	}
683
684	if( ( ptrA->yE + 1 ) >= ptrA->workScanRegionE.y2E - ( int32 )ptrA->patchHeightE ) return FALSE;
685
686	ptrA->xE = ptrA->workScanRegionE.x1E;
687	ptrA->yE++;
688
689	{
690		uint32 offL = ( ptrA->yE & 0x1F );
691		uint32 rowL = ( ptrA->yE >> 5 ) + ( offL > 0 ? 1 : 0 );
692
693		uint32 widthL = ptrA->bitImageE.widthE;
694		uint32 sizeL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E;
695		uint32* dstL = ( uint32* )ptrA->patchBufferE.arrPtrE + ptrA->xE;
696		uint32 iL;
697
698		if( rowL < ptrA->bitImageE.heightE )
699		{
700			uint32* srcL = ptrA->bitImageE.arrE.arrPtrE + rowL * widthL + ptrA->xE;
701			if( offL > 0 )
702			{
703				uint32 shlL = 32 - offL;
704				for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] = ( dstL[ iL ] >> 1 ) | ( srcL[ iL ] << shlL );
705			}
706			else
707			{
708				bbs_memcpy32( dstL, srcL, sizeL );
709			}
710		}
711		else
712		{
713			for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] >>= 1;
714		}
715	}
716
717	return TRUE;
718}
719
720/* ------------------------------------------------------------------------- */
721
722void bbf_LocalScanner_goToXY( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA, int32 xA, int32 yA )
723{
724	bbs_DEF_fNameL( "void bbf_LocalScanner_goToXY( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA, int32 xA, int32 yA )" )
725	if( xA < ptrA->workScanRegionE.x1E || xA >= ptrA->workScanRegionE.x2E - ( int32 )ptrA->patchWidthE )
726	{
727		bbs_ERROR1( "%s:\nxA out of range", fNameL );
728		return;
729	}
730	ptrA->xE = xA;
731	if( ptrA->yE == yA ) return;
732	if( yA < ptrA->workScanRegionE.y1E || yA >= ptrA->workScanRegionE.y2E - ( int32 )ptrA->patchHeightE )
733	{
734		bbs_ERROR1( "%s:\nyA out of range", fNameL );
735		return;
736	}
737	ptrA->yE = yA;
738
739	{
740		uint32 offL = ( ptrA->yE & 0x1F );
741		uint32 rowL = ( ptrA->yE >> 5 ) + ( offL > 0 ? 1 : 0 );
742
743		uint32 sizeL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E;
744		uint32 imgWidthL = ptrA->bitImageE.widthE;
745		uint32 imgOffsL = ptrA->workScanRegionE.x1E;
746		uint32* dstL = ptrA->patchBufferE.arrPtrE + imgOffsL;
747		uint32 iL;
748
749		if( rowL < ptrA->bitImageE.heightE )
750		{
751			if( offL > 0 )
752			{
753				uint32* src1L = ptrA->bitImageE.arrE.arrPtrE + rowL * imgWidthL + imgOffsL;
754				uint32* src0L = src1L - imgWidthL;
755				uint32 shlL = 32 - offL;
756				for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] = ( src0L[ iL ] >> offL ) | ( src1L[ iL ] << shlL );
757			}
758			else
759			{
760				bbs_memcpy32( dstL, ptrA->bitImageE.arrE.arrPtrE + rowL * imgWidthL + imgOffsL, sizeL );
761			}
762		}
763		else
764		{
765			uint32* srcL = ptrA->bitImageE.arrE.arrPtrE + ( rowL - 1 ) * imgWidthL + imgOffsL;
766			for( iL = 0; iL < sizeL; iL++ ) dstL[ iL ] = srcL[ iL ] >> offL;
767		}
768	}
769}
770
771/* ------------------------------------------------------------------------- */
772
773void bbf_LocalScanner_goToIndex( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA, uint32 scanIndexA )
774{
775	uint32 wL = ptrA->workScanRegionE.x2E - ptrA->workScanRegionE.x1E - ptrA->patchWidthE;
776	bbf_LocalScanner_goToXY( cpA, ptrA,
777							 ( scanIndexA % wL ) + ptrA->workScanRegionE.x1E,
778							 ( scanIndexA / wL ) + ptrA->workScanRegionE.y1E );
779}
780
781/* ------------------------------------------------------------------------- */
782
783flag bbf_LocalScanner_nextOffset( struct bbs_Context* cpA, struct bbf_LocalScanner* ptrA )
784{
785	int32 maxL = ( 1 << ptrA->scaleExpE );
786	if( ptrA->yOffE == maxL ) return FALSE;
787
788	ptrA->xOffE++;
789
790	if( ptrA->xOffE == maxL )
791	{
792		ptrA->xOffE = 0;
793		ptrA->yOffE++;
794		if( ptrA->yOffE == maxL ) return FALSE;
795	}
796
797	bbf_LocalScanner_downscale( cpA, ptrA );
798	bbf_LocalScanner_createBitImage( cpA, ptrA );
799	bbf_LocalScanner_setWorkScanRegion( cpA, ptrA );
800	bbf_LocalScanner_resetScan( cpA, ptrA );
801
802	return TRUE;
803}
804
805/* ------------------------------------------------------------------------- */
806
807/* ========================================================================= */
808