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