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) */
bim_downscaleBy2(uint8 * dstPtrA,const uint8 * srcPtrA,uint32 srcWidthA,uint32 effWidthA,uint32 effHeightA)38 void 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 
bim_filterWarpInterpolation(struct bbs_Context * cpA,uint8 * dstImagePtrA,const uint8 * srcImagePtrA,uint32 srcImageWidthA,uint32 srcImageHeightA,const struct bts_Int16Vec2D * offsPtrA,const struct bts_Flt16Alt2D * altPtrA,uint32 dstWidthA,uint32 dstHeightA,struct bbs_UInt8Arr * bufPtrA,uint32 scaleThresholdA)68 void 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 
bim_filterWarpPixelReplication(struct bbs_Context * cpA,uint8 * dstImagePtrA,const uint8 * srcImagePtrA,uint32 srcImageWidthA,uint32 srcImageHeightA,const struct bts_Int16Vec2D * offsPtrA,const struct bts_Flt16Alt2D * altPtrA,uint32 dstWidthA,uint32 dstHeightA,struct bbs_UInt8Arr * bufPtrA,uint32 scaleThresholdA)400 void 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 
bim_filterWarp(struct bbs_Context * cpA,uint8 * dstImagePtrA,const uint8 * srcImagePtrA,uint32 srcImageWidthA,uint32 srcImageHeightA,const struct bts_Int16Vec2D * offsPtrA,const struct bts_Flt16Alt2D * altPtrA,uint32 dstWidthA,uint32 dstHeightA,struct bbs_UInt8Arr * bufPtrA,uint32 scaleThresholdA,flag interpolateA)710 void 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