1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  *
22  * The bottom part of this is file is adapted from SDL_rotozoom.c. The
23  * relevant copyright notice for those specific functions can be found at the
24  * top of that section.
25  *
26  */
27 
28 #include "graphics/conversion.h"
29 #include "graphics/pixelformat.h"
30 #include "graphics/transform_struct.h"
31 
32 #include "common/endian.h"
33 #include "common/math.h"
34 #include "common/rect.h"
35 
36 namespace Graphics {
37 
38 // TODO: YUV to RGB conversion function
39 
40 // Function to blit a rect
copyBlit(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint w,const uint h,const uint bytesPerPixel)41 void copyBlit(byte *dst, const byte *src,
42 			   const uint dstPitch, const uint srcPitch,
43 			   const uint w, const uint h,
44 			   const uint bytesPerPixel) {
45 	if (dst == src)
46 		return;
47 
48 	if (dstPitch == srcPitch && ((w * bytesPerPixel) == dstPitch)) {
49 		memcpy(dst, src, dstPitch * h);
50 	} else {
51 		for (uint i = 0; i < h; ++i) {
52 			memcpy(dst, src, w * bytesPerPixel);
53 			dst += dstPitch;
54 			src += srcPitch;
55 		}
56 	}
57 }
58 
59 namespace {
60 
61 template<typename Size>
keyBlitLogic(byte * dst,const byte * src,const uint w,const uint h,const uint srcDelta,const uint dstDelta,const uint32 key)62 inline void keyBlitLogic(byte *dst, const byte *src, const uint w, const uint h,
63 						 const uint srcDelta, const uint dstDelta, const uint32 key) {
64 	for (uint y = 0; y < h; ++y) {
65 		for (uint x = 0; x < w; ++x) {
66 			uint32 color = *(const Size *)src;
67 			if (color != key)
68 				*(Size *)dst = color;
69 
70 			src += sizeof(Size);
71 			dst += sizeof(Size);
72 		}
73 
74 		src += srcDelta;
75 		dst += dstDelta;
76 	}
77 }
78 
79 } // End of anonymous namespace
80 
81 // Function to blit a rect with a transparent color key
keyBlit(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint w,const uint h,const uint bytesPerPixel,const uint32 key)82 bool keyBlit(byte *dst, const byte *src,
83 			   const uint dstPitch, const uint srcPitch,
84 			   const uint w, const uint h,
85 			   const uint bytesPerPixel, const uint32 key) {
86 	if (dst == src)
87 		return true;
88 
89 	// Faster, but larger, to provide optimized handling for each case.
90 	const uint srcDelta = (srcPitch - w * bytesPerPixel);
91 	const uint dstDelta = (dstPitch - w * bytesPerPixel);
92 
93 	if (bytesPerPixel == 1) {
94 		keyBlitLogic<uint8>(dst, src, w, h, srcDelta, dstDelta, key);
95 	} else if (bytesPerPixel == 2) {
96 		keyBlitLogic<uint16>(dst, src, w, h, srcDelta, dstDelta, key);
97 	} else if (bytesPerPixel == 4) {
98 		keyBlitLogic<uint32>(dst, src, w, h, srcDelta, dstDelta, key);
99 	} else {
100 		return false;
101 	}
102 
103 	return true;
104 }
105 
106 namespace {
107 
108 template<typename SrcColor, typename DstColor, bool backward>
crossBlitLogic(byte * dst,const byte * src,const uint w,const uint h,const PixelFormat & srcFmt,const PixelFormat & dstFmt,const uint srcDelta,const uint dstDelta)109 inline void crossBlitLogic(byte *dst, const byte *src, const uint w, const uint h,
110 						   const PixelFormat &srcFmt, const PixelFormat &dstFmt,
111 						   const uint srcDelta, const uint dstDelta) {
112 	for (uint y = 0; y < h; ++y) {
113 		for (uint x = 0; x < w; ++x) {
114 			const uint32 color = *(const SrcColor *)src;
115 			byte a, r, g, b;
116 			srcFmt.colorToARGB(color, a, r, g, b);
117 			*(DstColor *)dst = dstFmt.ARGBToColor(a, r, g, b);
118 
119 			if (backward) {
120 				src -= sizeof(SrcColor);
121 				dst -= sizeof(DstColor);
122 			} else {
123 				src += sizeof(SrcColor);
124 				dst += sizeof(DstColor);
125 			}
126 		}
127 
128 		if (backward) {
129 			src -= srcDelta;
130 			dst -= dstDelta;
131 		} else {
132 			src += srcDelta;
133 			dst += dstDelta;
134 		}
135 	}
136 }
137 
138 template<typename DstColor, bool backward>
crossBlitLogic1BppSource(byte * dst,const byte * src,const uint w,const uint h,const uint srcDelta,const uint dstDelta,const uint32 * map)139 inline void crossBlitLogic1BppSource(byte *dst, const byte *src, const uint w, const uint h,
140 									 const uint srcDelta, const uint dstDelta, const uint32 *map) {
141 	for (uint y = 0; y < h; ++y) {
142 		for (uint x = 0; x < w; ++x) {
143 			*(DstColor *)dst = map[*src];
144 
145 			if (backward) {
146 				src -= 1;
147 				dst -= sizeof(DstColor);
148 			} else {
149 				src += 1;
150 				dst += sizeof(DstColor);
151 			}
152 		}
153 
154 		if (backward) {
155 			src -= srcDelta;
156 			dst -= dstDelta;
157 		} else {
158 			src += srcDelta;
159 			dst += dstDelta;
160 		}
161 	}
162 }
163 
164 template<typename DstColor, bool backward>
crossBlitLogic3BppSource(byte * dst,const byte * src,const uint w,const uint h,const PixelFormat & srcFmt,const PixelFormat & dstFmt,const uint srcDelta,const uint dstDelta)165 inline void crossBlitLogic3BppSource(byte *dst, const byte *src, const uint w, const uint h,
166 									 const PixelFormat &srcFmt, const PixelFormat &dstFmt,
167 									 const uint srcDelta, const uint dstDelta) {
168 	uint32 color;
169 	byte r, g, b, a;
170 	uint8 *col = (uint8 *)&color;
171 #ifdef SCUMM_BIG_ENDIAN
172 	col++;
173 #endif
174 	for (uint y = 0; y < h; ++y) {
175 		for (uint x = 0; x < w; ++x) {
176 			memcpy(col, src, 3);
177 			srcFmt.colorToARGB(color, a, r, g, b);
178 			*(DstColor *)dst = dstFmt.ARGBToColor(a, r, g, b);
179 
180 			if (backward) {
181 				src -= 3;
182 				dst -= sizeof(DstColor);
183 			} else {
184 				src += 3;
185 				dst += sizeof(DstColor);
186 			}
187 		}
188 
189 		if (backward) {
190 			src -= srcDelta;
191 			dst -= dstDelta;
192 		} else {
193 			src += srcDelta;
194 			dst += dstDelta;
195 		}
196 	}
197 }
198 
199 } // End of anonymous namespace
200 
201 // Function to blit a rect from one color format to another
crossBlit(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint w,const uint h,const Graphics::PixelFormat & dstFmt,const Graphics::PixelFormat & srcFmt)202 bool crossBlit(byte *dst, const byte *src,
203 			   const uint dstPitch, const uint srcPitch,
204 			   const uint w, const uint h,
205 			   const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) {
206 	// Error out if conversion is impossible
207 	if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
208 			 || (dstFmt.bytesPerPixel == 3)
209 			 || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
210 		return false;
211 
212 	// Don't perform unnecessary conversion
213 	if (srcFmt == dstFmt) {
214 		copyBlit(dst, src, dstPitch, srcPitch, w, h, dstFmt.bytesPerPixel);
215 		return true;
216 	}
217 
218 	// Faster, but larger, to provide optimized handling for each case.
219 	const uint srcDelta = (srcPitch - w * srcFmt.bytesPerPixel);
220 	const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
221 
222 	// TODO: optimized cases for dstDelta of 0
223 	if (dstFmt.bytesPerPixel == 2) {
224 		if (srcFmt.bytesPerPixel == 2) {
225 			crossBlitLogic<uint16, uint16, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
226 		} else if (srcFmt.bytesPerPixel == 3) {
227 			crossBlitLogic3BppSource<uint16, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
228 		} else {
229 			crossBlitLogic<uint32, uint16, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
230 		}
231 	} else if (dstFmt.bytesPerPixel == 4) {
232 		if (srcFmt.bytesPerPixel == 2) {
233 			// We need to blit the surface from bottom right to top left here.
234 			// This is neeeded, because when we convert to the same memory
235 			// buffer copying the surface from top left to bottom right would
236 			// overwrite the source, since we have more bits per destination
237 			// color than per source color.
238 			dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
239 			src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
240 			crossBlitLogic<uint16, uint32, true>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
241 		} else if (srcFmt.bytesPerPixel == 3) {
242 			// We need to blit the surface from bottom right to top left here.
243 			// This is neeeded, because when we convert to the same memory
244 			// buffer copying the surface from top left to bottom right would
245 			// overwrite the source, since we have more bits per destination
246 			// color than per source color.
247 			dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
248 			src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
249 			crossBlitLogic3BppSource<uint32, true>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
250 		} else {
251 			crossBlitLogic<uint32, uint32, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta);
252 		}
253 	} else {
254 		return false;
255 	}
256 	return true;
257 }
258 
259 // Function to blit a rect from one color format to another using a map
crossBlitMap(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint w,const uint h,const uint bytesPerPixel,const uint32 * map)260 bool crossBlitMap(byte *dst, const byte *src,
261 			   const uint dstPitch, const uint srcPitch,
262 			   const uint w, const uint h,
263 			   const uint bytesPerPixel, const uint32 *map) {
264 	// Error out if conversion is impossible
265 	if ((bytesPerPixel == 3) || (!bytesPerPixel))
266 		return false;
267 
268 	// Faster, but larger, to provide optimized handling for each case.
269 	const uint srcDelta = (srcPitch - w);
270 	const uint dstDelta = (dstPitch - w * bytesPerPixel);
271 
272 	if (bytesPerPixel == 1) {
273 		crossBlitLogic1BppSource<uint8, false>(dst, src, w, h, srcDelta, dstDelta, map);
274 	} else if (bytesPerPixel == 2) {
275 		// We need to blit the surface from bottom right to top left here.
276 		// This is neeeded, because when we convert to the same memory
277 		// buffer copying the surface from top left to bottom right would
278 		// overwrite the source, since we have more bits per destination
279 		// color than per source color.
280 		dst += h * dstPitch - dstDelta - bytesPerPixel;
281 		src += h * srcPitch - srcDelta - 1;
282 		crossBlitLogic1BppSource<uint16, true>(dst, src, w, h, srcDelta, dstDelta, map);
283 	} else if (bytesPerPixel == 4) {
284 		// We need to blit the surface from bottom right to top left here.
285 		// This is neeeded, because when we convert to the same memory
286 		// buffer copying the surface from top left to bottom right would
287 		// overwrite the source, since we have more bits per destination
288 		// color than per source color.
289 		dst += h * dstPitch - dstDelta - bytesPerPixel;
290 		src += h * srcPitch - srcDelta - 1;
291 		crossBlitLogic1BppSource<uint32, true>(dst, src, w, h, srcDelta, dstDelta, map);
292 	} else {
293 		return false;
294 	}
295 	return true;
296 }
297 
298 namespace {
299 
300 template <typename Size>
scaleNN(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint dstW,const uint dstH,const uint srcW,const uint srcH,int * scaleCacheX)301 void scaleNN(byte *dst, const byte *src,
302 			   const uint dstPitch, const uint srcPitch,
303 			   const uint dstW, const uint dstH,
304 			   const uint srcW, const uint srcH,
305 			   int *scaleCacheX) {
306 
307 	const uint dstDelta = (dstPitch - dstW * sizeof(Size));
308 
309 	for (uint y = 0; y < dstH; y++) {
310 		const Size *srcP = (const Size *)(src + ((y * srcH) / dstH) * srcPitch);
311 		for (uint x = 0; x < dstW; x++) {
312 			int val = srcP[scaleCacheX[x]];
313 			*(Size *)dst = val;
314 			dst += sizeof(Size);
315 		}
316 		dst += dstDelta;
317 	}
318 }
319 
320 } // End of anonymous namespace
321 
scaleBlit(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint dstW,const uint dstH,const uint srcW,const uint srcH,const Graphics::PixelFormat & fmt)322 bool scaleBlit(byte *dst, const byte *src,
323 			   const uint dstPitch, const uint srcPitch,
324 			   const uint dstW, const uint dstH,
325 			   const uint srcW, const uint srcH,
326 			   const Graphics::PixelFormat &fmt) {
327 
328 	int *scaleCacheX = new int[dstW];
329 	for (uint x = 0; x < dstW; x++) {
330 		scaleCacheX[x] = (x * srcW) / dstW;
331 	}
332 
333 	switch (fmt.bytesPerPixel) {
334 	case 1:
335 		scaleNN<uint8>(dst, src, dstPitch, srcPitch, dstW,  dstH, srcW, srcH, scaleCacheX);
336 		break;
337 	case 2:
338 		scaleNN<uint16>(dst, src, dstPitch, srcPitch, dstW,  dstH, srcW, srcH, scaleCacheX);
339 		break;
340 	case 4:
341 		scaleNN<uint32>(dst, src, dstPitch, srcPitch, dstW,  dstH, srcW, srcH, scaleCacheX);
342 		break;
343 	default:
344 		delete[] scaleCacheX;
345 		return false;
346 	}
347 
348 	delete[] scaleCacheX;
349 
350 	return true;
351 }
352 
353 /*
354 
355 The functions below are adapted from SDL_rotozoom.c,
356 taken from SDL_gfx-2.0.18.
357 
358 Its copyright notice:
359 
360 =============================================================================
361 SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
362 
363 Copyright (C) 2001-2012  Andreas Schiffler
364 
365 This software is provided 'as-is', without any express or implied
366 warranty. In no event will the authors be held liable for any damages
367 arising from the use of this software.
368 
369 Permission is granted to anyone to use this software for any purpose,
370 including commercial applications, and to alter it and redistribute it
371 freely, subject to the following restrictions:
372 
373 1. The origin of this software must not be misrepresented; you must not
374 claim that you wrote the original software. If you use this software
375 in a product, an acknowledgment in the product documentation would be
376 appreciated but is not required.
377 
378 2. Altered source versions must be plainly marked as such, and must not be
379 misrepresented as being the original software.
380 
381 3. This notice may not be removed or altered from any source
382 distribution.
383 
384 Andreas Schiffler -- aschiffler at ferzkopp dot net
385 =============================================================================
386 
387 
388 The functions have been adapted for different structures, coordinate
389 systems and pixel formats.
390 
391 */
392 
393 namespace {
394 
scaleBlitBilinearInterpolate(byte c01,byte c00,byte c11,byte c10,int ex,int ey)395 inline byte scaleBlitBilinearInterpolate(byte c01, byte c00, byte c11, byte c10, int ex, int ey) {
396 	int t1 = ((((c01 - c00) * ex) >> 16) + c00) & 0xff;
397 	int t2 = ((((c11 - c10) * ex) >> 16) + c10) & 0xff;
398 	return (((t2 - t1) * ey) >> 16) + t1;
399 }
400 
401 template <typename ColorMask, typename Size>
scaleBlitBilinearInterpolate(Size c01,Size c00,Size c11,Size c10,int ex,int ey,const Graphics::PixelFormat & fmt)402 Size scaleBlitBilinearInterpolate(Size c01, Size c00, Size c11, Size c10, int ex, int ey,
403 								  const Graphics::PixelFormat &fmt) {
404 	byte c01_a, c01_r, c01_g, c01_b;
405 	fmt.colorToARGBT<ColorMask>(c01, c01_a, c01_r, c01_g, c01_b);
406 
407 	byte c00_a, c00_r, c00_g, c00_b;
408 	fmt.colorToARGBT<ColorMask>(c00, c00_a, c00_r, c00_g, c00_b);
409 
410 	byte c11_a, c11_r, c11_g, c11_b;
411 	fmt.colorToARGBT<ColorMask>(c11, c11_a, c11_r, c11_g, c11_b);
412 
413 	byte c10_a, c10_r, c10_g, c10_b;
414 	fmt.colorToARGBT<ColorMask>(c10, c10_a, c10_r, c10_g, c10_b);
415 
416 	byte dp_a = scaleBlitBilinearInterpolate(c01_a, c00_a, c11_a, c10_a, ex, ey);
417 	byte dp_r = scaleBlitBilinearInterpolate(c01_r, c00_r, c11_r, c10_r, ex, ey);
418 	byte dp_g = scaleBlitBilinearInterpolate(c01_g, c00_g, c11_g, c10_g, ex, ey);
419 	byte dp_b = scaleBlitBilinearInterpolate(c01_b, c00_b, c11_b, c10_b, ex, ey);
420 	return fmt.ARGBToColorT<ColorMask>(dp_a, dp_r, dp_g, dp_b);
421 }
422 
423 template <typename ColorMask, typename Size, bool flipx, bool flipy> // TODO: See mirroring comment in RenderTicket ctor
scaleBlitBilinearLogic(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint dstW,const uint dstH,const uint srcW,const uint srcH,const Graphics::PixelFormat & fmt,int * sax,int * say)424 void scaleBlitBilinearLogic(byte *dst, const byte *src,
425 							const uint dstPitch, const uint srcPitch,
426 							const uint dstW, const uint dstH,
427 							const uint srcW, const uint srcH,
428 							const Graphics::PixelFormat &fmt,
429 							int *sax, int *say) {
430 
431 	int spixelw = (srcW - 1);
432 	int spixelh = (srcH - 1);
433 
434 	const byte *sp = src;
435 
436 	if (flipx) {
437 		sp += spixelw;
438 	}
439 	if (flipy) {
440 		sp += srcPitch * spixelh;
441 	}
442 
443 	int *csay = say;
444 	for (uint y = 0; y < dstH; y++) {
445 		Size *dp = (Size *)(dst + (dstPitch * y));
446 		const byte *csp = sp;
447 		int *csax = sax;
448 		for (uint x = 0; x < dstW; x++) {
449 			/*
450 			* Setup color source pointers
451 			*/
452 			int ex = (*csax & 0xffff);
453 			int ey = (*csay & 0xffff);
454 			int cx = (*csax >> 16);
455 			int cy = (*csay >> 16);
456 
457 			const byte *c00, *c01, *c10, *c11;
458 			c00 = c01 = c10 = sp;
459 			if (cy < spixelh) {
460 				if (flipy) {
461 					c10 -= srcPitch;
462 				} else {
463 					c10 += srcPitch;
464 				}
465 			}
466 			c11 = c10;
467 			if (cx < spixelw) {
468 				if (flipx) {
469 					c01 -= sizeof(Size);
470 					c11 -= sizeof(Size);
471 				} else {
472 					c01 += sizeof(Size);
473 					c11 += sizeof(Size);
474 				}
475 			}
476 
477 			/*
478 			* Draw and interpolate colors
479 			*/
480 			*dp = scaleBlitBilinearInterpolate<ColorMask, Size>(*(const Size *)c01, *(const Size *)c00, *(const Size *)c11, *(const Size *)c10, ex, ey, fmt);
481 			/*
482 			* Advance source pointer x
483 			*/
484 			int *salastx = csax;
485 			csax++;
486 			int sstepx = (*csax >> 16) - (*salastx >> 16);
487 			if (flipx) {
488 				sp -= sstepx * sizeof(Size);
489 			} else {
490 				sp += sstepx * sizeof(Size);
491 			}
492 
493 			/*
494 			* Advance destination pointer x
495 			*/
496 			dp++;
497 		}
498 		/*
499 		* Advance source pointer y
500 		*/
501 		int *salasty = csay;
502 		csay++;
503 		int sstepy = (*csay >> 16) - (*salasty >> 16);
504 		sstepy *= srcPitch;
505 		if (flipy) {
506 			sp = csp - sstepy;
507 		} else {
508 			sp = csp + sstepy;
509 		}
510 	}
511 }
512 
513 template<typename ColorMask, typename Size, bool filtering, bool flipx, bool flipy> // TODO: See mirroring comment in RenderTicket ctor
rotoscaleBlitLogic(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint dstW,const uint dstH,const uint srcW,const uint srcH,const Graphics::PixelFormat & fmt,const TransformStruct & transform,const Common::Point & newHotspot)514 void rotoscaleBlitLogic(byte *dst, const byte *src,
515 						const uint dstPitch, const uint srcPitch,
516 						const uint dstW, const uint dstH,
517 						const uint srcW, const uint srcH,
518 						const Graphics::PixelFormat &fmt,
519 						const TransformStruct &transform,
520 						const Common::Point &newHotspot) {
521 
522 	assert(transform._angle != kDefaultAngle); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway.
523 
524 	if (transform._zoom.x == 0 || transform._zoom.y == 0) {
525 		return;
526 	}
527 
528 	uint32 invAngle = 360 - (transform._angle % 360);
529 	float invAngleRad = Common::deg2rad<uint32,float>(invAngle);
530 	float invCos = cos(invAngleRad);
531 	float invSin = sin(invAngleRad);
532 
533 	int icosx = (int)(invCos * (65536.0f * kDefaultZoomX / transform._zoom.x));
534 	int isinx = (int)(invSin * (65536.0f * kDefaultZoomX / transform._zoom.x));
535 	int icosy = (int)(invCos * (65536.0f * kDefaultZoomY / transform._zoom.y));
536 	int isiny = (int)(invSin * (65536.0f * kDefaultZoomY / transform._zoom.y));
537 
538 	int xd = transform._hotspot.x << 16;
539 	int yd = transform._hotspot.y << 16;
540 	int cx = newHotspot.x;
541 	int cy = newHotspot.y;
542 
543 	int ax = -icosx * cx;
544 	int ay = -isiny * cx;
545 	int sw = srcW - 1;
546 	int sh = srcH - 1;
547 
548 	Size *pc = (Size *)dst;
549 
550 	for (uint y = 0; y < dstH; y++) {
551 		int t = cy - y;
552 		int sdx = ax + (isinx * t) + xd;
553 		int sdy = ay - (icosy * t) + yd;
554 		for (uint x = 0; x < dstW; x++) {
555 			int dx = (sdx >> 16);
556 			int dy = (sdy >> 16);
557 			if (flipx) {
558 				dx = sw - dx;
559 			}
560 			if (flipy) {
561 				dy = sh - dy;
562 			}
563 
564 			if (filtering) {
565 				if ((dx > -1) && (dy > -1) && (dx < sw) && (dy < sh)) {
566 					const byte *sp = src + dy * srcPitch + dx * sizeof(Size);
567 					Size c00, c01, c10, c11;
568 					c00 = *(const Size *)sp;
569 					sp += sizeof(Size);
570 					c01 = *(const Size *)sp;
571 					sp += srcPitch;
572 					c11 = *(const Size *)sp;
573 					sp -= sizeof(Size);
574 					c10 = *(const Size *)sp;
575 					if (flipx) {
576 						SWAP(c00, c01);
577 						SWAP(c10, c11);
578 					}
579 					if (flipy) {
580 						SWAP(c00, c10);
581 						SWAP(c01, c11);
582 					}
583 					/*
584 					* Interpolate colors
585 					*/
586 					int ex = (sdx & 0xffff);
587 					int ey = (sdy & 0xffff);
588 					*pc = scaleBlitBilinearInterpolate<ColorMask, Size>(c01, c00, c11, c10, ex, ey, fmt);
589 				}
590 			} else {
591 				if ((dx >= 0) && (dy >= 0) && (dx < (int)srcW) && (dy < (int)srcH)) {
592 					const byte *sp = src + dy * srcPitch + dx * sizeof(Size);
593 					*pc = *(const Size *)sp;
594 				}
595 			}
596 			sdx += icosx;
597 			sdy += isiny;
598 			pc++;
599 		}
600 	}
601 }
602 
603 } // End of anonymous namespace
604 
scaleBlitBilinear(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint dstW,const uint dstH,const uint srcW,const uint srcH,const Graphics::PixelFormat & fmt)605 bool scaleBlitBilinear(byte *dst, const byte *src,
606 					   const uint dstPitch, const uint srcPitch,
607 					   const uint dstW, const uint dstH,
608 					   const uint srcW, const uint srcH,
609 					   const Graphics::PixelFormat &fmt) {
610 	if (fmt.bytesPerPixel != 2 && fmt.bytesPerPixel != 4)
611 		return false;
612 
613 	int *sax = new int[dstW + 1];
614 	int *say = new int[dstH + 1];
615 	assert(sax && say);
616 
617 	/*
618 	* Precalculate row increments
619 	*/
620 	int spixelw = (srcW - 1);
621 	int spixelh = (srcH - 1);
622 	int sx = (int)(65536.0f * (float) spixelw / (float) (dstW - 1));
623 	int sy = (int)(65536.0f * (float) spixelh / (float) (dstH - 1));
624 
625 	/* Maximum scaled source size */
626 	int ssx = (srcW << 16) - 1;
627 	int ssy = (srcH << 16) - 1;
628 
629 	/* Precalculate horizontal row increments */
630 	int csx = 0;
631 	int *csax = sax;
632 	for (uint x = 0; x <= dstW; x++) {
633 		*csax = csx;
634 		csax++;
635 		csx += sx;
636 
637 		/* Guard from overflows */
638 		if (csx > ssx) {
639 			csx = ssx;
640 		}
641 	}
642 
643 	/* Precalculate vertical row increments */
644 	int csy = 0;
645 	int *csay = say;
646 	for (uint y = 0; y <= dstH; y++) {
647 		*csay = csy;
648 		csay++;
649 		csy += sy;
650 
651 		/* Guard from overflows */
652 		if (csy > ssy) {
653 			csy = ssy;
654 		}
655 	}
656 
657 	if (fmt == createPixelFormat<8888>()) {
658 		scaleBlitBilinearLogic<ColorMasks<8888>, uint32, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say);
659 	} else if (fmt == createPixelFormat<888>()) {
660 		scaleBlitBilinearLogic<ColorMasks<888>,  uint32, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say);
661 	} else if (fmt == createPixelFormat<565>()) {
662 		scaleBlitBilinearLogic<ColorMasks<565>,  uint16, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say);
663 	} else if (fmt == createPixelFormat<555>()) {
664 		scaleBlitBilinearLogic<ColorMasks<555>,  uint16, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say);
665 
666 	} else if (fmt.bytesPerPixel == 4) {
667 		scaleBlitBilinearLogic<ColorMasks<0>,    uint32, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say);
668 	} else if (fmt.bytesPerPixel == 2) {
669 		scaleBlitBilinearLogic<ColorMasks<0>,    uint16, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say);
670 	} else {
671 		delete[] sax;
672 		delete[] say;
673 
674 		return false;
675 	}
676 
677 	delete[] sax;
678 	delete[] say;
679 
680 	return true;
681 }
682 
rotoscaleBlit(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint dstW,const uint dstH,const uint srcW,const uint srcH,const Graphics::PixelFormat & fmt,const TransformStruct & transform,const Common::Point & newHotspot)683 bool rotoscaleBlit(byte *dst, const byte *src,
684 				   const uint dstPitch, const uint srcPitch,
685 				   const uint dstW, const uint dstH,
686 				   const uint srcW, const uint srcH,
687 				   const Graphics::PixelFormat &fmt,
688 				   const TransformStruct &transform,
689 				   const Common::Point &newHotspot) {
690 	if (fmt.bytesPerPixel == 4) {
691 		rotoscaleBlitLogic<ColorMasks<0>, uint32, false, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot);
692 	} else if (fmt.bytesPerPixel == 2) {
693 		rotoscaleBlitLogic<ColorMasks<0>, uint16, false, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot);
694 	} else if (fmt.bytesPerPixel == 1) {
695 		rotoscaleBlitLogic<ColorMasks<0>, uint8, false, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot);
696 	} else {
697 		return false;
698 	}
699 
700 	return true;
701 }
702 
rotoscaleBlitBilinear(byte * dst,const byte * src,const uint dstPitch,const uint srcPitch,const uint dstW,const uint dstH,const uint srcW,const uint srcH,const Graphics::PixelFormat & fmt,const TransformStruct & transform,const Common::Point & newHotspot)703 bool rotoscaleBlitBilinear(byte *dst, const byte *src,
704 						   const uint dstPitch, const uint srcPitch,
705 						   const uint dstW, const uint dstH,
706 						   const uint srcW, const uint srcH,
707 						   const Graphics::PixelFormat &fmt,
708 						   const TransformStruct &transform,
709 						   const Common::Point &newHotspot) {
710 	if (fmt == createPixelFormat<8888>()) {
711 		rotoscaleBlitLogic<ColorMasks<8888>, uint32, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot);
712 	} else if (fmt == createPixelFormat<888>()) {
713 		rotoscaleBlitLogic<ColorMasks<888>,  uint32, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot);
714 	} else if (fmt == createPixelFormat<565>()) {
715 		rotoscaleBlitLogic<ColorMasks<565>,  uint16, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot);
716 	} else if (fmt == createPixelFormat<555>()) {
717 		rotoscaleBlitLogic<ColorMasks<555>,  uint16, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot);
718 
719 	} else if (fmt.bytesPerPixel == 4) {
720 		rotoscaleBlitLogic<ColorMasks<0>,    uint32, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot);
721 	} else if (fmt.bytesPerPixel == 2) {
722 		rotoscaleBlitLogic<ColorMasks<0>,    uint16, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot);
723 	} else {
724 		return false;
725 	}
726 
727 	return true;
728 }
729 
730 } // End of namespace Graphics
731