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_ImageEm/Functions.h"
20
21/* ---- related objects  --------------------------------------------------- */
22
23/* ---- typedefs ----------------------------------------------------------- */
24
25/* ---- constants ---------------------------------------------------------- */
26
27/* ------------------------------------------------------------------------- */
28
29/* ========================================================================= */
30/*                                                                           */
31/* ---- \ghd{ external functions } ----------------------------------------- */
32/*                                                                           */
33/* ========================================================================= */
34
35/* ------------------------------------------------------------------------- */
36
37/** downscale by factor 2 (dstPtrA and srcPtrA may be identical) */
38void bim_downscaleBy2( uint8*       dstPtrA,
39					   const uint8* srcPtrA,
40					   uint32 srcWidthA,
41					   uint32 effWidthA,
42					   uint32 effHeightA )
43{
44	uint32 wsL = srcWidthA;
45	uint32 w0L = effWidthA;
46	uint32 h0L = effHeightA;
47	uint32 w1L = w0L >> 1;
48	uint32 h1L = h0L >> 1;
49
50	const uint8* srcL = srcPtrA;
51	uint8* dstL = dstPtrA;
52
53	uint32 iL, jL;
54	for( jL = 0; jL < h1L; jL++ )
55	{
56		for( iL = 0; iL < w1L; iL++ )
57		{
58			*dstL = ( ( uint32 )srcL[ 0 ] + srcL[ 1 ] + srcL[ wsL ] + srcL[ wsL + 1 ] + 2 ) >> 2;
59			dstL++;
60			srcL += 2;
61		}
62		srcL += ( wsL - w1L ) * 2;
63	}
64}
65
66/* ------------------------------------------------------------------------- */
67
68void bim_filterWarpInterpolation( struct bbs_Context* cpA,
69								  uint8* dstImagePtrA,
70								  const uint8* srcImagePtrA,
71								  uint32 srcImageWidthA,
72								  uint32 srcImageHeightA,
73							      const struct bts_Int16Vec2D* offsPtrA,
74								  const struct bts_Flt16Alt2D* altPtrA,
75								  uint32 dstWidthA,
76								  uint32 dstHeightA,
77								  struct bbs_UInt8Arr* bufPtrA,
78								  uint32 scaleThresholdA )
79{
80	bbs_DEF_fNameL( "bim_filterWarpInterpolation" )
81
82	uint32 w0L = srcImageWidthA;
83	uint32 h0L = srcImageHeightA;
84
85	const uint8* srcL = srcImagePtrA;
86	uint8* dstL = dstImagePtrA;
87
88	uint32 w1L = w0L;
89	uint32 h1L = h0L;
90
91	/* 16.16 */
92	uint32 scaleThrL = scaleThresholdA;
93	struct bts_Flt16Alt2D invAltL;
94
95	/* matrix variables */
96	int32 mxxL, mxyL, myxL, myyL, txL, tyL;
97
98	flag downScaledL = FALSE;
99	flag boundsOkL = TRUE;
100
101	if( w0L == 0 || h0L == 0 || bts_Flt16Mat2D_det( &altPtrA->matE ) == 0 )
102	{
103		uint32 iL;
104		for( iL = 0; iL < dstWidthA * dstHeightA; iL++ ) dstImagePtrA[ iL ] = 0;
105		return;
106	}
107
108	/* compute inverse ALT */
109	invAltL = bts_Flt16Alt2D_inverted( altPtrA );
110
111	/* fixed point ALT 16.16 */
112	if( invAltL.matE.bbpE <= 16 )
113	{
114		uint32 shlL = 16 - invAltL.matE.bbpE;
115		mxxL = invAltL.matE.xxE << shlL;
116		mxyL = invAltL.matE.xyE << shlL;
117		myxL = invAltL.matE.yxE << shlL;
118		myyL = invAltL.matE.yyE << shlL;
119	}
120	else
121	{
122		uint32 shrL = invAltL.matE.bbpE - 16;
123		mxxL = ( ( invAltL.matE.xxE >> ( shrL - 1 ) ) + 1 ) >> 1;
124		mxyL = ( ( invAltL.matE.xyE >> ( shrL - 1 ) ) + 1 ) >> 1;
125		myxL = ( ( invAltL.matE.yxE >> ( shrL - 1 ) ) + 1 ) >> 1;
126		myyL = ( ( invAltL.matE.yyE >> ( shrL - 1 ) ) + 1 ) >> 1;
127	}
128
129	if( invAltL.vecE.bbpE <= 16 )
130	{
131		uint32 shlL = 16 - invAltL.vecE.bbpE;
132		txL = invAltL.vecE.xE << shlL;
133		tyL = invAltL.vecE.yE << shlL;
134	}
135	else
136	{
137		uint32 shrL = invAltL.vecE.bbpE - 16;
138		txL = ( ( invAltL.vecE.xE >> ( shrL - 1 ) ) + 1 ) >> 1;
139		tyL = ( ( invAltL.vecE.yE >> ( shrL - 1 ) ) + 1 ) >> 1;
140	}
141
142	/* add offset */
143	txL += ( int32 )offsPtrA->xE << 16;
144	tyL += ( int32 )offsPtrA->yE << 16;
145
146	if( scaleThresholdA > 0 )
147	{
148		/* compute downscale exponent */
149		uint32 axxL = ( mxxL >= 0 ) ? mxxL : -mxxL;
150		uint32 axyL = ( mxyL >= 0 ) ? mxyL : -mxyL;
151		uint32 ayxL = ( myxL >= 0 ) ? myxL : -myxL;
152		uint32 ayyL = ( myyL >= 0 ) ? myyL : -myyL;
153
154		uint32 a1L = ( axxL > ayxL ) ? axxL : ayxL;
155		uint32 a2L = ( axyL > ayyL ) ? axyL : ayyL;
156
157		uint32 invScaleL = ( a1L < a2L ) ? a1L : a2L;
158		uint32 scaleExpL = 0;
159		while( ( invScaleL >> scaleExpL ) > scaleThrL ) scaleExpL++;
160		while( ( scaleExpL > 0 ) && ( w0L >> scaleExpL ) < 2 ) scaleExpL--;
161		while( ( scaleExpL > 0 ) && ( h0L >> scaleExpL ) < 2 ) scaleExpL--;
162
163		/* downscale image */
164		if( scaleExpL > 0 )
165		{
166			/* down sampling is limited to the effective area of the original image */
167
168			/* compute effective area by mapping all corners of the dst rectangle */
169			int32 xMinL = 0x7FFFFFFF;
170			int32 yMinL = 0x7FFFFFFF;
171			int32 xMaxL = 0x80000000;
172			int32 yMaxL = 0x80000000;
173			uint32 wEffL, hEffL;
174
175			{
176				int32 xL, yL;
177				xL = txL;
178				yL = tyL;
179				xMinL = xL < xMinL ? xL : xMinL;
180				yMinL = yL < yMinL ? yL : yMinL;
181				xMaxL = xL > xMaxL ? xL : xMaxL;
182				yMaxL = yL > yMaxL ? yL : yMaxL;
183				xL = txL + mxxL * ( int32 )dstWidthA + mxyL * ( int32 )dstHeightA;
184				yL = tyL + myxL * ( int32 )dstWidthA + myyL * ( int32 )dstHeightA;
185				xMinL = xL < xMinL ? xL : xMinL;
186				yMinL = yL < yMinL ? yL : yMinL;
187				xMaxL = xL > xMaxL ? xL : xMaxL;
188				yMaxL = yL > yMaxL ? yL : yMaxL;
189				xL = txL + mxyL * ( int32 )dstHeightA;
190				yL = tyL + myyL * ( int32 )dstHeightA;
191				xMinL = xL < xMinL ? xL : xMinL;
192				yMinL = yL < yMinL ? yL : yMinL;
193				xMaxL = xL > xMaxL ? xL : xMaxL;
194				yMaxL = yL > yMaxL ? yL : yMaxL;
195				xL = txL + mxxL * ( int32 )dstWidthA;
196				yL = tyL + myxL * ( int32 )dstWidthA;
197				xMinL = xL < xMinL ? xL : xMinL;
198				yMinL = yL < yMinL ? yL : yMinL;
199				xMaxL = xL > xMaxL ? xL : xMaxL;
200				yMaxL = yL > yMaxL ? yL : yMaxL;
201			}
202
203			xMaxL = ( xMaxL >> 16 ) + 2;
204			yMaxL = ( yMaxL >> 16 ) + 2;
205			xMinL >>= 16;
206			yMinL >>= 16;
207
208			/* ensre effective area stays within original frame */
209			xMinL = 0 > xMinL ? 0 : xMinL;
210			yMinL = 0 > yMinL ? 0 : yMinL;
211			xMinL = ( int32 )w0L < xMinL ? w0L : xMinL;
212			yMinL = ( int32 )h0L < yMinL ? h0L : yMinL;
213			xMaxL = 0 > xMaxL ? 0 : xMaxL;
214			yMaxL = 0 > yMaxL ? 0 : yMaxL;
215			xMaxL = ( int32 )w0L < xMaxL ? w0L : xMaxL;
216			yMaxL = ( int32 )h0L < yMaxL ? h0L : yMaxL;
217
218			wEffL = xMaxL - xMinL;
219			hEffL = yMaxL - yMinL;
220
221			/* ensure downscaling does not reduce image to 0 */
222			while( ( scaleExpL > 0 ) && ( wEffL >> scaleExpL ) < 2 ) scaleExpL--;
223			while( ( scaleExpL > 0 ) && ( hEffL >> scaleExpL ) < 2 ) scaleExpL--;
224
225			/* downscale */
226			if( scaleExpL > 0 )
227			{
228				uint32 iL;
229				w1L = wEffL >> 1;
230				h1L = hEffL >> 1;
231				if( bufPtrA == NULL ) bbs_ERROR1( "%s:\nPreallocated buffer is needed", fNameL );
232				bbs_UInt8Arr_size( cpA, bufPtrA, w1L * h1L );
233				bim_downscaleBy2( bufPtrA->arrPtrE, srcL + yMinL * w0L + xMinL, w0L, wEffL, hEffL );
234				for( iL = 1; iL < scaleExpL; iL++ )
235				{
236					bim_downscaleBy2( bufPtrA->arrPtrE, bufPtrA->arrPtrE, w1L, w1L, h1L );
237					w1L >>= 1;
238					h1L >>= 1;
239				}
240
241				/* adjust inverted cordinates */
242				txL -= ( xMinL << 16 );
243				tyL -= ( yMinL << 16 );
244				mxxL >>= scaleExpL;
245				mxyL >>= scaleExpL;
246				myxL >>= scaleExpL;
247				myyL >>= scaleExpL;
248				txL >>= scaleExpL;
249				tyL >>= scaleExpL;
250				srcL = bufPtrA->arrPtrE;
251			}
252
253			downScaledL = TRUE;
254		}
255	}
256
257	/* if not downscaled and src and dst images are identcal then copy srcImage into buffer */
258	if( !downScaledL && dstImagePtrA == srcImagePtrA )
259	{
260		uint32 iL;
261		uint32 srcSizeL = srcImageWidthA * srcImageHeightA;
262		if( bufPtrA == NULL ) bbs_ERROR1( "%s:\nPreallocated buffer is needed", fNameL );
263		bbs_UInt8Arr_size( cpA, bufPtrA, srcSizeL );
264		for( iL = 0; iL < srcSizeL; iL++ ) bufPtrA->arrPtrE[ iL ] = srcImagePtrA[ iL ];
265		srcL = bufPtrA->arrPtrE;
266	}
267
268	/* compute destination image */
269
270	/* bounds check (dst image fully inside src image? -> fast algorithm) */
271	{
272		int32 xL, yL;
273		int32 wbL = w1L - 1;
274		int32 hbL = h1L - 1;
275
276		xL = txL >> 16;
277		yL = tyL >> 16;
278		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
279
280		xL = ( txL + mxxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
281		yL = ( tyL + myxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
282		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
283
284		xL = ( txL + mxyL * ( int32 )( dstHeightA - 1 ) ) >> 16;
285		yL = ( tyL + myyL * ( int32 )( dstHeightA - 1 ) ) >> 16;
286		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
287
288		xL = ( txL + mxyL * ( int32 )( dstHeightA - 1 ) + mxxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
289		yL = ( tyL + myyL * ( int32 )( dstHeightA - 1 ) + myxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
290		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
291	}
292
293	if( boundsOkL )
294	{
295		int32 iL, jL;
296		for( jL = 0; jL < ( int32 )dstHeightA; jL++ )
297		{
298			/* 16.16 */
299			int32 xL = txL + mxyL * jL;
300			int32 yL = tyL + myyL * jL;
301			for( iL = 0; iL < ( int32 )dstWidthA; iL++ )
302			{
303				int32 x0L = xL >> 16;
304				int32 y0L = yL >> 16;
305				uint32 xf2L = xL & 0x0FFFF;
306				uint32 yf2L = yL & 0x0FFFF;
307				uint32 xf1L = 0x10000 - xf2L;
308				uint32 yf1L = 0x10000 - yf2L;
309
310				xL += mxxL;
311				yL += myxL;
312
313				{
314					uint32 idxL = y0L * w1L + x0L;
315					uint32 v1L = ( ( uint32 )srcL[ idxL       ] * xf1L + ( uint32 )srcL[ idxL + 1       ] * xf2L + 0x0800 ) >> 12;
316					uint32 v2L = ( ( uint32 )srcL[ idxL + w1L ] * xf1L + ( uint32 )srcL[ idxL + w1L + 1 ] * xf2L + 0x0800 ) >> 12;
317					*dstL++ = ( v1L * yf1L + v2L * yf2L + 0x080000 ) >> 20;
318				}
319			}
320		}
321	}
322	else
323	{
324		int32 iL, jL;
325		for( jL = 0; jL < ( int32 )dstHeightA; jL++ )
326		{
327			/* 16.16 */
328			int32 xL = txL + mxyL * jL;
329			int32 yL = tyL + myyL * jL;
330			for( iL = 0; iL < ( int32 )dstWidthA; iL++ )
331			{
332				int32 x0L = xL >> 16;
333				int32 y0L = yL >> 16;
334				uint32 xf2L = xL & 0x0FFFF;
335				uint32 yf2L = yL & 0x0FFFF;
336				uint32 xf1L = 0x10000 - xf2L;
337				uint32 yf1L = 0x10000 - yf2L;
338
339				xL += mxxL;
340				yL += myxL;
341
342				if( y0L < 0 )
343				{
344					if( x0L < 0 )
345					{
346						*dstL++ = srcL[ 0 ];
347					}
348					else if( x0L >= ( int32 )w1L - 1 )
349					{
350						*dstL++ = srcL[ w1L - 1 ];
351					}
352					else
353					{
354						*dstL++ = ( ( uint32 )srcL[ x0L ] * xf1L + ( uint32 )srcL[ x0L + 1 ] * xf2L + 0x08000 ) >> 16;
355					}
356				}
357				else if( y0L >= ( int32 )h1L - 1 )
358				{
359					if( x0L < 0 )
360					{
361						*dstL++ = srcL[ ( h1L - 1 ) * w1L ];
362					}
363					else if( x0L >= ( int32 )w1L - 1 )
364					{
365						*dstL++ = srcL[ ( h1L * w1L ) - 1 ];
366					}
367					else
368					{
369						uint32 idxL = ( h1L - 1 ) * w1L + x0L;
370						*dstL++ = ( ( uint32 )srcL[ idxL ] * xf1L + ( uint32 )srcL[ idxL + 1 ] * xf2L + 0x08000 ) >> 16;
371					}
372				}
373				else
374				{
375					if( x0L < 0 )
376					{
377						uint32 idxL = y0L * w1L;
378						*dstL++ = ( ( uint32 )srcL[ idxL ] * yf1L + ( uint32 )srcL[ idxL + w1L ] * yf2L + 0x08000 ) >> 16;
379					}
380					else if( x0L >= ( int32 )w1L - 1 )
381					{
382						uint32 idxL = ( y0L + 1 ) * w1L - 1;
383						*dstL++ = ( ( uint32 )srcL[ idxL ] * yf1L + ( uint32 )srcL[ idxL + w1L ] * yf2L + 0x08000 ) >> 16;
384					}
385					else
386					{
387						uint32 idxL = y0L * w1L + x0L;
388						uint32 v1L = ( ( uint32 )srcL[ idxL       ] * xf1L + ( uint32 )srcL[ idxL + 1       ] * xf2L + 0x0800 ) >> 12;
389						uint32 v2L = ( ( uint32 )srcL[ idxL + w1L ] * xf1L + ( uint32 )srcL[ idxL + w1L + 1 ] * xf2L + 0x0800 ) >> 12;
390						*dstL++ = ( v1L * yf1L + v2L * yf2L + 0x080000 ) >> 20;
391					}
392				}
393			}
394		}
395	}
396}
397
398/* ------------------------------------------------------------------------- */
399
400void bim_filterWarpPixelReplication( struct bbs_Context* cpA,
401								     uint8* dstImagePtrA,
402								     const uint8* srcImagePtrA,
403								     uint32 srcImageWidthA,
404								     uint32 srcImageHeightA,
405								     const struct bts_Int16Vec2D* offsPtrA,
406								     const struct bts_Flt16Alt2D* altPtrA,
407								     uint32 dstWidthA,
408								     uint32 dstHeightA,
409								     struct bbs_UInt8Arr* bufPtrA,
410								     uint32 scaleThresholdA )
411{
412	bbs_DEF_fNameL( "bim_filterWarpPixelReplication" )
413
414	uint32 w0L = srcImageWidthA;
415	uint32 h0L = srcImageHeightA;
416
417	const uint8* srcL = srcImagePtrA;
418	uint8* dstL = dstImagePtrA;
419
420	uint32 w1L = w0L;
421	uint32 h1L = h0L;
422
423	/* 16.16 */
424	uint32 scaleThrL = scaleThresholdA;
425	struct bts_Flt16Alt2D invAltL;
426
427	/* matrix variables */
428	int32 mxxL, mxyL, myxL, myyL, txL, tyL;
429
430	flag downScaledL = FALSE;
431	flag boundsOkL = TRUE;
432
433	if( w0L == 0 || h0L == 0 || bts_Flt16Mat2D_det( &altPtrA->matE ) == 0 )
434	{
435		uint32 iL;
436		for( iL = 0; iL < dstWidthA * dstHeightA; iL++ ) dstImagePtrA[ iL ] = 0;
437		return;
438	}
439
440	/* compute inverse ALT */
441	invAltL = bts_Flt16Alt2D_inverted( altPtrA );
442
443	/* fixed point ALT 16.16 */
444	if( invAltL.matE.bbpE <= 16 )
445	{
446		uint32 shlL = 16 - invAltL.matE.bbpE;
447		mxxL = invAltL.matE.xxE << shlL;
448		mxyL = invAltL.matE.xyE << shlL;
449		myxL = invAltL.matE.yxE << shlL;
450		myyL = invAltL.matE.yyE << shlL;
451	}
452	else
453	{
454		uint32 shrL = invAltL.matE.bbpE - 16;
455		mxxL = ( ( invAltL.matE.xxE >> ( shrL - 1 ) ) + 1 ) >> 1;
456		mxyL = ( ( invAltL.matE.xyE >> ( shrL - 1 ) ) + 1 ) >> 1;
457		myxL = ( ( invAltL.matE.yxE >> ( shrL - 1 ) ) + 1 ) >> 1;
458		myyL = ( ( invAltL.matE.yyE >> ( shrL - 1 ) ) + 1 ) >> 1;
459	}
460
461	if( invAltL.vecE.bbpE <= 16 )
462	{
463		uint32 shlL = 16 - invAltL.vecE.bbpE;
464		txL = invAltL.vecE.xE << shlL;
465		tyL = invAltL.vecE.yE << shlL;
466	}
467	else
468	{
469		uint32 shrL = invAltL.vecE.bbpE - 16;
470		txL = ( ( invAltL.vecE.xE >> ( shrL - 1 ) ) + 1 ) >> 1;
471		tyL = ( ( invAltL.vecE.yE >> ( shrL - 1 ) ) + 1 ) >> 1;
472	}
473
474	/* add offset */
475	txL += ( int32 )offsPtrA->xE << 16;
476	tyL += ( int32 )offsPtrA->yE << 16;
477
478	if( scaleThresholdA > 0 )
479	{
480		/* compute downscale exponent */
481		uint32 axxL = ( mxxL >= 0 ) ? mxxL : -mxxL;
482		uint32 axyL = ( mxyL >= 0 ) ? mxyL : -mxyL;
483		uint32 ayxL = ( myxL >= 0 ) ? myxL : -myxL;
484		uint32 ayyL = ( myyL >= 0 ) ? myyL : -myyL;
485
486		uint32 a1L = ( axxL > ayxL ) ? axxL : ayxL;
487		uint32 a2L = ( axyL > ayyL ) ? axyL : ayyL;
488
489		uint32 invScaleL = ( a1L < a2L ) ? a1L : a2L;
490		uint32 scaleExpL = 0;
491		while( ( invScaleL >> scaleExpL ) > scaleThrL ) scaleExpL++;
492		while( ( scaleExpL > 0 ) && ( w0L >> scaleExpL ) < 2 ) scaleExpL--;
493		while( ( scaleExpL > 0 ) && ( h0L >> scaleExpL ) < 2 ) scaleExpL--;
494
495		/* downscale image */
496		if( scaleExpL > 0 )
497		{
498			/* down sampling is limited to the effective area of the original image */
499
500			/* compute effective area by mapping all corners of the dst rectangle */
501			int32 xMinL = 0x7FFFFFFF;
502			int32 yMinL = 0x7FFFFFFF;
503			int32 xMaxL = 0x80000000;
504			int32 yMaxL = 0x80000000;
505			uint32 wEffL, hEffL;
506
507			{
508				int32 xL, yL;
509				xL = txL;
510				yL = tyL;
511				xMinL = xL < xMinL ? xL : xMinL;
512				yMinL = yL < yMinL ? yL : yMinL;
513				xMaxL = xL > xMaxL ? xL : xMaxL;
514				yMaxL = yL > yMaxL ? yL : yMaxL;
515				xL = txL + mxxL * ( int32 )dstWidthA + mxyL * ( int32 )dstHeightA;
516				yL = tyL + myxL * ( int32 )dstWidthA + myyL * ( int32 )dstHeightA;
517				xMinL = xL < xMinL ? xL : xMinL;
518				yMinL = yL < yMinL ? yL : yMinL;
519				xMaxL = xL > xMaxL ? xL : xMaxL;
520				yMaxL = yL > yMaxL ? yL : yMaxL;
521				xL = txL + mxyL * ( int32 )dstHeightA;
522				yL = tyL + myyL * ( int32 )dstHeightA;
523				xMinL = xL < xMinL ? xL : xMinL;
524				yMinL = yL < yMinL ? yL : yMinL;
525				xMaxL = xL > xMaxL ? xL : xMaxL;
526				yMaxL = yL > yMaxL ? yL : yMaxL;
527				xL = txL + mxxL * ( int32 )dstWidthA;
528				yL = tyL + myxL * ( int32 )dstWidthA;
529				xMinL = xL < xMinL ? xL : xMinL;
530				yMinL = yL < yMinL ? yL : yMinL;
531				xMaxL = xL > xMaxL ? xL : xMaxL;
532				yMaxL = yL > yMaxL ? yL : yMaxL;
533			}
534
535			xMaxL = ( xMaxL >> 16 ) + 2;
536			yMaxL = ( yMaxL >> 16 ) + 2;
537			xMinL >>= 16;
538			yMinL >>= 16;
539
540			/* ensre effective area stays within original frame */
541			xMinL = 0 > xMinL ? 0 : xMinL;
542			yMinL = 0 > yMinL ? 0 : yMinL;
543			xMinL = ( int32 )w0L < xMinL ? w0L : xMinL;
544			yMinL = ( int32 )h0L < yMinL ? h0L : yMinL;
545			xMaxL = 0 > xMaxL ? 0 : xMaxL;
546			yMaxL = 0 > yMaxL ? 0 : yMaxL;
547			xMaxL = ( int32 )w0L < xMaxL ? w0L : xMaxL;
548			yMaxL = ( int32 )h0L < yMaxL ? h0L : yMaxL;
549
550			wEffL = xMaxL - xMinL;
551			hEffL = yMaxL - yMinL;
552
553			/* ensure downscaling does not reduce image to 0 */
554			while( ( scaleExpL > 0 ) && ( wEffL >> scaleExpL ) < 2 ) scaleExpL--;
555			while( ( scaleExpL > 0 ) && ( hEffL >> scaleExpL ) < 2 ) scaleExpL--;
556
557			/* downscale */
558			if( scaleExpL > 0 )
559			{
560				uint32 iL;
561				w1L = wEffL >> 1;
562				h1L = hEffL >> 1;
563				if( bufPtrA == NULL ) bbs_ERROR1( "%s:\nPreallocated buffer is needed", fNameL );
564				bbs_UInt8Arr_size( cpA, bufPtrA, w1L * h1L );
565				bim_downscaleBy2( bufPtrA->arrPtrE, srcL + yMinL * w0L + xMinL, w0L, wEffL, hEffL );
566				for( iL = 1; iL < scaleExpL; iL++ )
567				{
568					bim_downscaleBy2( bufPtrA->arrPtrE, bufPtrA->arrPtrE, w1L, w1L, h1L );
569					w1L >>= 1;
570					h1L >>= 1;
571				}
572
573				/* adjust inverted cordinates */
574				txL -= ( xMinL << 16 );
575				tyL -= ( yMinL << 16 );
576				mxxL >>= scaleExpL;
577				mxyL >>= scaleExpL;
578				myxL >>= scaleExpL;
579				myyL >>= scaleExpL;
580				txL >>= scaleExpL;
581				tyL >>= scaleExpL;
582				srcL = bufPtrA->arrPtrE;
583			}
584
585			downScaledL = TRUE;
586		}
587	}
588
589	/* if not downscaled and src and dst images are identcal then copy srcImage into buffer */
590	if( !downScaledL && dstImagePtrA == srcImagePtrA )
591	{
592		uint32 iL;
593		uint32 srcSizeL = srcImageWidthA * srcImageHeightA;
594		if( bufPtrA == NULL ) bbs_ERROR1( "%s:\nPreallocated buffer is needed", fNameL );
595		bbs_UInt8Arr_size( cpA, bufPtrA, srcSizeL );
596		for( iL = 0; iL < srcSizeL; iL++ ) bufPtrA->arrPtrE[ iL ] = srcImagePtrA[ iL ];
597		srcL = bufPtrA->arrPtrE;
598	}
599
600	/* compute destination image */
601
602	/* bounds check (dst image fully inside src image? -> fast algorithm) */
603	{
604		int32 xL, yL;
605		int32 wbL = w1L - 1;
606		int32 hbL = h1L - 1;
607
608		xL = txL >> 16;
609		yL = tyL >> 16;
610		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
611
612		xL = ( txL + mxxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
613		yL = ( tyL + myxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
614		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
615
616		xL = ( txL + mxyL * ( int32 )( dstHeightA - 1 ) ) >> 16;
617		yL = ( tyL + myyL * ( int32 )( dstHeightA - 1 ) ) >> 16;
618		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
619
620		xL = ( txL + mxyL * ( int32 )( dstHeightA - 1 ) + mxxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
621		yL = ( tyL + myyL * ( int32 )( dstHeightA - 1 ) + myxL * ( int32 )( dstWidthA - 1 ) ) >> 16;
622		boundsOkL = boundsOkL && ( xL >= 0 && xL < wbL && yL >= 0 && yL < hbL );
623	}
624
625	if( boundsOkL )
626	{
627		int32 iL, jL;
628		for( jL = 0; jL < ( int32 )dstHeightA; jL++ )
629		{
630			/* 16.16 */
631			int32 xL = txL + mxyL * jL;
632			int32 yL = tyL + myyL * jL;
633			for( iL = 0; iL < ( int32 )dstWidthA; iL++ )
634			{
635				/* nearest whole position */
636				*dstL++ = srcL[ ( ( ( yL >> 15 ) + 1 ) >> 1 ) * w1L + ( ( ( xL >> 15 ) + 1 ) >> 1 ) ];
637				xL += mxxL;
638				yL += myxL;
639			}
640		}
641	}
642	else
643	{
644		int32 iL, jL;
645		for( jL = 0; jL < ( int32 )dstHeightA; jL++ )
646		{
647			/* 16.16 */
648			int32 xL = txL + mxyL * jL;
649			int32 yL = tyL + myyL * jL;
650			for( iL = 0; iL < ( int32 )dstWidthA; iL++ )
651			{
652				/* nearest whole position */
653				int32 x0L = ( ( xL >> 15 ) + 1 ) >> 1;
654				int32 y0L = ( ( yL >> 15 ) + 1 ) >> 1;
655				xL += mxxL;
656				yL += myxL;
657
658				if( y0L < 0 )
659				{
660					if( x0L < 0 )
661					{
662						*dstL++ = srcL[ 0 ];
663					}
664					else if( x0L >= ( int32 )w1L - 1 )
665					{
666						*dstL++ = srcL[ w1L - 1 ];
667					}
668					else
669					{
670						*dstL++ = srcL[ x0L ];
671					}
672				}
673				else if( y0L >= ( int32 )h1L - 1 )
674				{
675					if( x0L < 0 )
676					{
677						*dstL++ = srcL[ ( h1L - 1 ) * w1L ];
678					}
679					else if( x0L >= ( int32 )w1L - 1 )
680					{
681						*dstL++ = srcL[ ( h1L * w1L ) - 1 ];
682					}
683					else
684					{
685						*dstL++ = srcL[ ( h1L - 1 ) * w1L + x0L ];
686					}
687				}
688				else
689				{
690					if( x0L < 0 )
691					{
692						*dstL++ = srcL[ y0L * w1L ];
693					}
694					else if( x0L >= ( int32 )w1L - 1 )
695					{
696						*dstL++ = srcL[ ( y0L + 1 ) * w1L - 1 ];
697					}
698					else
699					{
700						*dstL++ = srcL[ y0L * w1L + x0L ];
701					}
702				}
703			}
704		}
705	}
706}
707
708/* ------------------------------------------------------------------------- */
709
710void bim_filterWarp( struct bbs_Context* cpA,
711					 uint8* dstImagePtrA,
712					 const uint8* srcImagePtrA,
713					 uint32 srcImageWidthA,
714					 uint32 srcImageHeightA,
715				     const struct bts_Int16Vec2D* offsPtrA,
716					 const struct bts_Flt16Alt2D* altPtrA,
717					 uint32 dstWidthA,
718					 uint32 dstHeightA,
719					 struct bbs_UInt8Arr* bufPtrA,
720					 uint32 scaleThresholdA,
721					 flag interpolateA )
722{
723	if( interpolateA )
724	{
725		bim_filterWarpInterpolation( cpA, dstImagePtrA, srcImagePtrA, srcImageWidthA, srcImageHeightA, offsPtrA, altPtrA, dstWidthA, dstHeightA, bufPtrA, scaleThresholdA );
726	}
727	else
728	{
729		bim_filterWarpPixelReplication( cpA, dstImagePtrA, srcImagePtrA, srcImageWidthA, srcImageHeightA, offsPtrA, altPtrA, dstWidthA, dstHeightA, bufPtrA, scaleThresholdA );
730	}
731}
732
733/* ------------------------------------------------------------------------- */
734
735