~ubuntu-branches/ubuntu/trusty/manaplus/trusty-proposed

« back to all changes in this revision

Viewing changes to src/sdl2gfx/SDL_rotozoom.c

  • Committer: Package Import Robot
  • Author(s): Patrick Matthäi
  • Date: 2013-09-17 10:35:51 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20130917103551-az7p3nz9jgxwqjfn
Tags: 1.3.9.15-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  
 
2
 
 
3
SDL2_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
 
4
 
 
5
Copyright (C) 2012  Andreas Schiffler
 
6
 
 
7
This software is provided 'as-is', without any express or implied
 
8
warranty. In no event will the authors be held liable for any damages
 
9
arising from the use of this software.
 
10
 
 
11
Permission is granted to anyone to use this software for any purpose,
 
12
including commercial applications, and to alter it and redistribute it
 
13
freely, subject to the following restrictions:
 
14
 
 
15
1. The origin of this software must not be misrepresented; you must not
 
16
claim that you wrote the original software. If you use this software
 
17
in a product, an acknowledgment in the product documentation would be
 
18
appreciated but is not required.
 
19
 
 
20
2. Altered source versions must be plainly marked as such, and must not be
 
21
misrepresented as being the original software.
 
22
 
 
23
3. This notice may not be removed or altered from any source
 
24
distribution.
 
25
 
 
26
Andreas Schiffler -- aschiffler at ferzkopp dot net
 
27
 
 
28
*/
 
29
 
 
30
#ifdef WIN32
 
31
#include <windows.h>
 
32
#endif
 
33
 
 
34
#include <stdlib.h>
 
35
#include <string.h>
 
36
 
 
37
#include "SDL_rotozoom.h"
 
38
 
 
39
/* ---- Internally used structures */
 
40
 
 
41
/*!
 
42
\brief A 32 bit RGBA pixel.
 
43
*/
 
44
typedef struct tColorRGBA {
 
45
        Uint8 r;
 
46
        Uint8 g;
 
47
        Uint8 b;
 
48
        Uint8 a;
 
49
} tColorRGBA;
 
50
 
 
51
/*!
 
52
\brief A 8bit Y/palette pixel.
 
53
*/
 
54
typedef struct tColorY {
 
55
        Uint8 y;
 
56
} tColorY;
 
57
 
 
58
/*! 
 
59
\brief Returns maximum of two numbers a and b.
 
60
*/
 
61
#define MAX(a,b)    (((a) > (b)) ? (a) : (b))
 
62
 
 
63
/*! 
 
64
\brief Number of guard rows added to destination surfaces.
 
65
 
 
66
This is a simple but effective workaround for observed issues.
 
67
These rows allocate extra memory and are then hidden from the surface.
 
68
Rows are added to the end of destination surfaces when they are allocated. 
 
69
This catches any potential overflows which seem to happen with 
 
70
just the right src image dimensions and scale/rotation and can lead
 
71
to a situation where the program can segfault.
 
72
*/
 
73
#define GUARD_ROWS (2)
 
74
 
 
75
/*!
 
76
\brief Lower limit of absolute zoom factor or rotation degrees.
 
77
*/
 
78
#define VALUE_LIMIT     0.001
 
79
 
 
80
/*!
 
81
\brief Returns colorkey info for a surface
 
82
*/
 
83
Uint32 _colorkey(SDL_Surface *src)
 
84
{
 
85
        Uint32 key = 0; 
 
86
        SDL_GetColorKey(src, &key);
 
87
        return key;
 
88
}
 
89
 
 
90
 
 
91
/*! 
 
92
\brief Internal 32 bit integer-factor averaging Shrinker.
 
93
 
 
94
Shrinks 32 bit RGBA/ABGR 'src' surface to 'dst' surface.
 
95
Averages color and alpha values values of src pixels to calculate dst pixels.
 
96
Assumes src and dst surfaces are of 32 bit depth.
 
97
Assumes dst surface was allocated with the correct dimensions.
 
98
 
 
99
\param src The surface to shrink (input).
 
100
\param dst The shrunken surface (output).
 
101
\param factorx The horizontal shrinking ratio.
 
102
\param factory The vertical shrinking ratio.
 
103
 
 
104
\return 0 for success or -1 for error.
 
105
*/
 
106
int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
 
107
{
 
108
        int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
 
109
        int n_average;
 
110
        tColorRGBA *sp, *osp, *oosp;
 
111
        tColorRGBA *dp;
 
112
 
 
113
        /*
 
114
        * Averaging integer shrink
 
115
        */
 
116
 
 
117
        /* Precalculate division factor */
 
118
        n_average = factorx*factory;
 
119
 
 
120
        /*
 
121
        * Scan destination
 
122
        */
 
123
        sp = (tColorRGBA *) src->pixels;
 
124
        sgap = src->pitch - src->w * 4;
 
125
 
 
126
        dp = (tColorRGBA *) dst->pixels;
 
127
        dgap = dst->pitch - dst->w * 4;
 
128
 
 
129
        for (y = 0; y < dst->h; y++) {
 
130
 
 
131
                osp=sp;
 
132
                for (x = 0; x < dst->w; x++) {
 
133
 
 
134
                        /* Trace out source box and accumulate */
 
135
                        oosp=sp;
 
136
                        ra=ga=ba=aa=0;
 
137
                        for (dy=0; dy < factory; dy++) {
 
138
                                for (dx=0; dx < factorx; dx++) {
 
139
                                        ra += sp->r;
 
140
                                        ga += sp->g;
 
141
                                        ba += sp->b;
 
142
                                        aa += sp->a;
 
143
 
 
144
                                        sp++;
 
145
                                } 
 
146
                                /* src dx loop */
 
147
                                sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
 
148
                        }
 
149
                        /* src dy loop */
 
150
 
 
151
                        /* next box-x */
 
152
                        sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
 
153
 
 
154
                        /* Store result in destination */
 
155
                        dp->r = ra/n_average;
 
156
                        dp->g = ga/n_average;
 
157
                        dp->b = ba/n_average;
 
158
                        dp->a = aa/n_average;
 
159
 
 
160
                        /*
 
161
                        * Advance destination pointer 
 
162
                        */
 
163
                        dp++;
 
164
                } 
 
165
                /* dst x loop */
 
166
 
 
167
                /* next box-y */
 
168
                sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
 
169
 
 
170
                /*
 
171
                * Advance destination pointers 
 
172
                */
 
173
                dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
 
174
        } 
 
175
        /* dst y loop */
 
176
 
 
177
        return (0);
 
178
}
 
179
 
 
180
/*! 
 
181
\brief Internal 8 bit integer-factor averaging shrinker.
 
182
 
 
183
Shrinks 8bit Y 'src' surface to 'dst' surface.
 
184
Averages color (brightness) values values of src pixels to calculate dst pixels.
 
185
Assumes src and dst surfaces are of 8 bit depth.
 
186
Assumes dst surface was allocated with the correct dimensions.
 
187
 
 
188
\param src The surface to shrink (input).
 
189
\param dst The shrunken surface (output).
 
190
\param factorx The horizontal shrinking ratio.
 
191
\param factory The vertical shrinking ratio.
 
192
 
 
193
\return 0 for success or -1 for error.
 
194
*/
 
195
int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
 
196
{
 
197
        int x, y, dx, dy, sgap, dgap, a;
 
198
        int n_average;
 
199
        Uint8 *sp, *osp, *oosp;
 
200
        Uint8 *dp;
 
201
 
 
202
        /*
 
203
        * Averaging integer shrink
 
204
        */
 
205
 
 
206
        /* Precalculate division factor */
 
207
        n_average = factorx*factory;
 
208
 
 
209
        /*
 
210
        * Scan destination
 
211
        */
 
212
        sp = (Uint8 *) src->pixels;
 
213
        sgap = src->pitch - src->w;
 
214
 
 
215
        dp = (Uint8 *) dst->pixels;
 
216
        dgap = dst->pitch - dst->w;
 
217
 
 
218
        for (y = 0; y < dst->h; y++) {    
 
219
 
 
220
                osp=sp;
 
221
                for (x = 0; x < dst->w; x++) {
 
222
 
 
223
                        /* Trace out source box and accumulate */
 
224
                        oosp=sp;
 
225
                        a=0;
 
226
                        for (dy=0; dy < factory; dy++) {
 
227
                                for (dx=0; dx < factorx; dx++) {
 
228
                                        a += (*sp);
 
229
                                        /* next x */           
 
230
                                        sp++;
 
231
                                } 
 
232
                                /* end src dx loop */         
 
233
                                /* next y */
 
234
                                sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx)); 
 
235
                        } 
 
236
                        /* end src dy loop */
 
237
 
 
238
                        /* next box-x */
 
239
                        sp = (Uint8 *)((Uint8*)oosp + factorx);
 
240
 
 
241
                        /* Store result in destination */
 
242
                        *dp = a/n_average;
 
243
 
 
244
                        /*
 
245
                        * Advance destination pointer 
 
246
                        */
 
247
                        dp++;
 
248
                } 
 
249
                /* end dst x loop */
 
250
 
 
251
                /* next box-y */
 
252
                sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
 
253
 
 
254
                /*
 
255
                * Advance destination pointers 
 
256
                */
 
257
                dp = (Uint8 *)((Uint8 *)dp + dgap);
 
258
        } 
 
259
        /* end dst y loop */
 
260
 
 
261
        return (0);
 
262
}
 
263
 
 
264
/*! 
 
265
\brief Internal 32 bit Zoomer with optional anti-aliasing by bilinear interpolation.
 
266
 
 
267
Zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface.
 
268
Assumes src and dst surfaces are of 32 bit depth.
 
269
Assumes dst surface was allocated with the correct dimensions.
 
270
 
 
271
\param src The surface to zoom (input).
 
272
\param dst The zoomed surface (output).
 
273
\param flipx Flag indicating if the image should be horizontally flipped.
 
274
\param flipy Flag indicating if the image should be vertically flipped.
 
275
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
 
276
 
 
277
\return 0 for success or -1 for error.
 
278
*/
 
279
int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
 
280
{
 
281
        int x, y, sx, sy, ssx, ssy, *sax, *say, *csax, *csay, *salast, csx, csy, ex, ey, cx, cy, sstep, sstepx, sstepy;
 
282
        tColorRGBA *c00, *c01, *c10, *c11;
 
283
        tColorRGBA *sp, *csp, *dp;
 
284
        int spixelgap, spixelw, spixelh, dgap, t1, t2;
 
285
 
 
286
        /*
 
287
        * Allocate memory for row/column increments 
 
288
        */
 
289
        if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
 
290
                return (-1);
 
291
        }
 
292
        if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
 
293
                free(sax);
 
294
                return (-1);
 
295
        }
 
296
 
 
297
        /*
 
298
        * Precalculate row increments 
 
299
        */
 
300
        spixelw = (src->w - 1);
 
301
        spixelh = (src->h - 1);
 
302
        if (smooth) {
 
303
                sx = (int) (65536.0 * (float) spixelw / (float) (dst->w - 1));
 
304
                sy = (int) (65536.0 * (float) spixelh / (float) (dst->h - 1));
 
305
        } else {
 
306
                sx = (int) (65536.0 * (float) (src->w) / (float) (dst->w));
 
307
                sy = (int) (65536.0 * (float) (src->h) / (float) (dst->h));
 
308
        }
 
309
 
 
310
        /* Maximum scaled source size */
 
311
        ssx = (src->w << 16) - 1;
 
312
        ssy = (src->h << 16) - 1;
 
313
 
 
314
        /* Precalculate horizontal row increments */
 
315
        csx = 0;
 
316
        csax = sax;
 
317
        for (x = 0; x <= dst->w; x++) {
 
318
                *csax = csx;
 
319
                csax++;
 
320
                csx += sx;
 
321
 
 
322
                /* Guard from overflows */
 
323
                if (csx > ssx) { 
 
324
                        csx = ssx; 
 
325
                }
 
326
        }
 
327
 
 
328
        /* Precalculate vertical row increments */
 
329
        csy = 0;
 
330
        csay = say;
 
331
        for (y = 0; y <= dst->h; y++) {
 
332
                *csay = csy;
 
333
                csay++;
 
334
                csy += sy;
 
335
 
 
336
                /* Guard from overflows */
 
337
                if (csy > ssy) {
 
338
                        csy = ssy;
 
339
                }
 
340
        }
 
341
 
 
342
        sp = (tColorRGBA *) src->pixels;
 
343
        dp = (tColorRGBA *) dst->pixels;
 
344
        dgap = dst->pitch - dst->w * 4;
 
345
        spixelgap = src->pitch/4;
 
346
 
 
347
        if (flipx) sp += spixelw;
 
348
        if (flipy) sp += (spixelgap * spixelh);
 
349
 
 
350
        /*
 
351
        * Switch between interpolating and non-interpolating code 
 
352
        */
 
353
        if (smooth) {
 
354
 
 
355
                /*
 
356
                * Interpolating Zoom 
 
357
                */
 
358
                csay = say;
 
359
                for (y = 0; y < dst->h; y++) {
 
360
                        csp = sp;
 
361
                        csax = sax;
 
362
                        for (x = 0; x < dst->w; x++) {
 
363
                                /*
 
364
                                * Setup color source pointers 
 
365
                                */
 
366
                                ex = (*csax & 0xffff);
 
367
                                ey = (*csay & 0xffff);
 
368
                                cx = (*csax >> 16);
 
369
                                cy = (*csay >> 16);
 
370
                                sstepx = cx < spixelw;
 
371
                                sstepy = cy < spixelh;
 
372
                                c00 = sp;
 
373
                                c01 = sp;
 
374
                                c10 = sp;
 
375
                                if (sstepy) {
 
376
                                        if (flipy) {
 
377
                                                c10 -= spixelgap;
 
378
                                        } else {
 
379
                                                c10 += spixelgap;
 
380
                                        }
 
381
                                }
 
382
                                c11 = c10;
 
383
                                if (sstepx) {
 
384
                                        if (flipx) {
 
385
                                                c01--;
 
386
                                                c11--;
 
387
                                        } else {
 
388
                                                c01++;
 
389
                                                c11++;
 
390
                                        }
 
391
                                }
 
392
 
 
393
                                /*
 
394
                                * Draw and interpolate colors 
 
395
                                */
 
396
                                t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
 
397
                                t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
 
398
                                dp->r = (((t2 - t1) * ey) >> 16) + t1;
 
399
                                t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
 
400
                                t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
 
401
                                dp->g = (((t2 - t1) * ey) >> 16) + t1;
 
402
                                t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
 
403
                                t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
 
404
                                dp->b = (((t2 - t1) * ey) >> 16) + t1;
 
405
                                t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
 
406
                                t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
 
407
                                dp->a = (((t2 - t1) * ey) >> 16) + t1;                          
 
408
                                /*
 
409
                                * Advance source pointer x
 
410
                                */
 
411
                                salast = csax;
 
412
                                csax++;                         
 
413
                                sstep = (*csax >> 16) - (*salast >> 16);
 
414
                                if (flipx) {
 
415
                                        sp -= sstep;
 
416
                                } else {
 
417
                                        sp += sstep;
 
418
                                }
 
419
 
 
420
                                /*
 
421
                                * Advance destination pointer x
 
422
                                */
 
423
                                dp++;
 
424
                        }
 
425
                        /*
 
426
                        * Advance source pointer y
 
427
                        */
 
428
                        salast = csay;
 
429
                        csay++;
 
430
                        sstep = (*csay >> 16) - (*salast >> 16);
 
431
                        sstep *= spixelgap;
 
432
                        if (flipy) { 
 
433
                                sp = csp - sstep;
 
434
                        } else {
 
435
                                sp = csp + sstep;
 
436
                        }
 
437
 
 
438
                        /*
 
439
                        * Advance destination pointer y
 
440
                        */
 
441
                        dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
 
442
                }
 
443
        } else {
 
444
                /*
 
445
                * Non-Interpolating Zoom 
 
446
                */              
 
447
                csay = say;
 
448
                for (y = 0; y < dst->h; y++) {
 
449
                        csp = sp;
 
450
                        csax = sax;
 
451
                        for (x = 0; x < dst->w; x++) {
 
452
                                /*
 
453
                                * Draw 
 
454
                                */
 
455
                                *dp = *sp;
 
456
 
 
457
                                /*
 
458
                                * Advance source pointer x
 
459
                                */
 
460
                                salast = csax;
 
461
                                csax++;                         
 
462
                                sstep = (*csax >> 16) - (*salast >> 16);
 
463
                                if (flipx) sstep = -sstep;
 
464
                                sp += sstep;
 
465
 
 
466
                                /*
 
467
                                * Advance destination pointer x
 
468
                                */
 
469
                                dp++;
 
470
                        }
 
471
                        /*
 
472
                        * Advance source pointer y
 
473
                        */
 
474
                        salast = csay;
 
475
                        csay++;
 
476
                        sstep = (*csay >> 16) - (*salast >> 16);
 
477
                        sstep *= spixelgap;
 
478
                        if (flipy) sstep = -sstep;                      
 
479
                        sp = csp + sstep;
 
480
 
 
481
                        /*
 
482
                        * Advance destination pointer y
 
483
                        */
 
484
                        dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
 
485
                }
 
486
        }
 
487
 
 
488
        /*
 
489
        * Remove temp arrays 
 
490
        */
 
491
        free(sax);
 
492
        free(say);
 
493
 
 
494
        return (0);
 
495
}
 
496
 
 
497
/*! 
 
498
 
 
499
\brief Internal 8 bit Zoomer without smoothing.
 
500
 
 
501
Zooms 8bit palette/Y 'src' surface to 'dst' surface.
 
502
Assumes src and dst surfaces are of 8 bit depth.
 
503
Assumes dst surface was allocated with the correct dimensions.
 
504
 
 
505
\param src The surface to zoom (input).
 
506
\param dst The zoomed surface (output).
 
507
\param flipx Flag indicating if the image should be horizontally flipped.
 
508
\param flipy Flag indicating if the image should be vertically flipped.
 
509
 
 
510
\return 0 for success or -1 for error.
 
511
*/
 
512
int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
 
513
{
 
514
        int x, y;
 
515
        Uint32 *sax, *say, *csax, *csay;
 
516
        int csx, csy;
 
517
        Uint8 *sp, *dp, *csp;
 
518
        int dgap;
 
519
 
 
520
        /*
 
521
        * Allocate memory for row increments 
 
522
        */
 
523
        if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
 
524
                return (-1);
 
525
        }
 
526
        if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
 
527
                free(sax);
 
528
                return (-1);
 
529
        }
 
530
 
 
531
        /*
 
532
        * Pointer setup 
 
533
        */
 
534
        sp = csp = (Uint8 *) src->pixels;
 
535
        dp = (Uint8 *) dst->pixels;
 
536
        dgap = dst->pitch - dst->w;
 
537
 
 
538
        if (flipx) csp += (src->w-1);
 
539
        if (flipy) csp  = ( (Uint8*)csp + src->pitch*(src->h-1) );
 
540
 
 
541
        /*
 
542
        * Precalculate row increments 
 
543
        */
 
544
        csx = 0;
 
545
        csax = sax;
 
546
        for (x = 0; x < dst->w; x++) {
 
547
                csx += src->w;
 
548
                *csax = 0;
 
549
                while (csx >= dst->w) {
 
550
                        csx -= dst->w;
 
551
                        (*csax)++;
 
552
                }
 
553
                (*csax) = (*csax) * (flipx ? -1 : 1);
 
554
                csax++;
 
555
        }
 
556
        csy = 0;
 
557
        csay = say;
 
558
        for (y = 0; y < dst->h; y++) {
 
559
                csy += src->h;
 
560
                *csay = 0;
 
561
                while (csy >= dst->h) {
 
562
                        csy -= dst->h;
 
563
                        (*csay)++;
 
564
                }
 
565
                (*csay) = (*csay) * (flipy ? -1 : 1);
 
566
                csay++;
 
567
        }
 
568
 
 
569
        /*
 
570
        * Draw 
 
571
        */
 
572
        csay = say;
 
573
        for (y = 0; y < dst->h; y++) {
 
574
                csax = sax;
 
575
                sp = csp;
 
576
                for (x = 0; x < dst->w; x++) {
 
577
                        /*
 
578
                        * Draw 
 
579
                        */
 
580
                        *dp = *sp;
 
581
                        /*
 
582
                        * Advance source pointers 
 
583
                        */
 
584
                        sp += (*csax);
 
585
                        csax++;
 
586
                        /*
 
587
                        * Advance destination pointer 
 
588
                        */
 
589
                        dp++;
 
590
                }
 
591
                /*
 
592
                * Advance source pointer (for row) 
 
593
                */
 
594
                csp += ((*csay) * src->pitch);
 
595
                csay++;
 
596
 
 
597
                /*
 
598
                * Advance destination pointers 
 
599
                */
 
600
                dp += dgap;
 
601
        }
 
602
 
 
603
        /*
 
604
        * Remove temp arrays 
 
605
        */
 
606
        free(sax);
 
607
        free(say);
 
608
 
 
609
        return (0);
 
610
}
 
611
 
 
612
/*! 
 
613
\brief Internal 32 bit rotozoomer with optional anti-aliasing.
 
614
 
 
615
Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control 
 
616
parameters by scanning the destination surface and applying optionally anti-aliasing
 
617
by bilinear interpolation.
 
618
Assumes src and dst surfaces are of 32 bit depth.
 
619
Assumes dst surface was allocated with the correct dimensions.
 
620
 
 
621
\param src Source surface.
 
622
\param dst Destination surface.
 
623
\param cx Horizontal center coordinate.
 
624
\param cy Vertical center coordinate.
 
625
\param isin Integer version of sine of angle.
 
626
\param icos Integer version of cosine of angle.
 
627
\param flipx Flag indicating horizontal mirroring should be applied.
 
628
\param flipy Flag indicating vertical mirroring should be applied.
 
629
\param smooth Flag indicating anti-aliasing should be used.
 
630
*/
 
631
void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
 
632
{
 
633
        int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
 
634
        tColorRGBA c00, c01, c10, c11, cswap;
 
635
        tColorRGBA *pc, *sp;
 
636
        int gap;
 
637
 
 
638
        /*
 
639
        * Variable setup 
 
640
        */
 
641
        xd = ((src->w - dst->w) << 15);
 
642
        yd = ((src->h - dst->h) << 15);
 
643
        ax = (cx << 16) - (icos * cx);
 
644
        ay = (cy << 16) - (isin * cx);
 
645
        sw = src->w - 1;
 
646
        sh = src->h - 1;
 
647
        pc = (tColorRGBA*) dst->pixels;
 
648
        gap = dst->pitch - dst->w * 4;
 
649
 
 
650
        /*
 
651
        * Switch between interpolating and non-interpolating code 
 
652
        */
 
653
        if (smooth) {
 
654
                for (y = 0; y < dst->h; y++) {
 
655
                        dy = cy - y;
 
656
                        sdx = (ax + (isin * dy)) + xd;
 
657
                        sdy = (ay - (icos * dy)) + yd;
 
658
                        for (x = 0; x < dst->w; x++) {
 
659
                                dx = (sdx >> 16);
 
660
                                dy = (sdy >> 16);
 
661
                                if (flipx) dx = sw - dx;
 
662
                                if (flipy) dy = sh - dy;
 
663
                                if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) {
 
664
                                        sp = (tColorRGBA *)src->pixels;;
 
665
                                        sp += ((src->pitch/4) * dy);
 
666
                                        sp += dx;
 
667
                                        c00 = *sp;
 
668
                                        sp += 1;
 
669
                                        c01 = *sp;
 
670
                                        sp += (src->pitch/4);
 
671
                                        c11 = *sp;
 
672
                                        sp -= 1;
 
673
                                        c10 = *sp;
 
674
                                        if (flipx) {
 
675
                                                cswap = c00; c00=c01; c01=cswap;
 
676
                                                cswap = c10; c10=c11; c11=cswap;
 
677
                                        }
 
678
                                        if (flipy) {
 
679
                                                cswap = c00; c00=c10; c10=cswap;
 
680
                                                cswap = c01; c01=c11; c11=cswap;
 
681
                                        }
 
682
                                        /*
 
683
                                        * Interpolate colors 
 
684
                                        */
 
685
                                        ex = (sdx & 0xffff);
 
686
                                        ey = (sdy & 0xffff);
 
687
                                        t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
 
688
                                        t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
 
689
                                        pc->r = (((t2 - t1) * ey) >> 16) + t1;
 
690
                                        t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
 
691
                                        t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
 
692
                                        pc->g = (((t2 - t1) * ey) >> 16) + t1;
 
693
                                        t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
 
694
                                        t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
 
695
                                        pc->b = (((t2 - t1) * ey) >> 16) + t1;
 
696
                                        t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
 
697
                                        t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
 
698
                                        pc->a = (((t2 - t1) * ey) >> 16) + t1;
 
699
                                }
 
700
                                sdx += icos;
 
701
                                sdy += isin;
 
702
                                pc++;
 
703
                        }
 
704
                        pc = (tColorRGBA *) ((Uint8 *) pc + gap);
 
705
                }
 
706
        } else {
 
707
                for (y = 0; y < dst->h; y++) {
 
708
                        dy = cy - y;
 
709
                        sdx = (ax + (isin * dy)) + xd;
 
710
                        sdy = (ay - (icos * dy)) + yd;
 
711
                        for (x = 0; x < dst->w; x++) {
 
712
                                dx = (short) (sdx >> 16);
 
713
                                dy = (short) (sdy >> 16);
 
714
                                if (flipx) dx = (src->w-1)-dx;
 
715
                                if (flipy) dy = (src->h-1)-dy;
 
716
                                if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
 
717
                                        sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
 
718
                                        sp += dx;
 
719
                                        *pc = *sp;
 
720
                                }
 
721
                                sdx += icos;
 
722
                                sdy += isin;
 
723
                                pc++;
 
724
                        }
 
725
                        pc = (tColorRGBA *) ((Uint8 *) pc + gap);
 
726
                }
 
727
        }
 
728
}
 
729
 
 
730
/*!
 
731
 
 
732
\brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
 
733
 
 
734
Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control 
 
735
parameters by scanning the destination surface.
 
736
Assumes src and dst surfaces are of 8 bit depth.
 
737
Assumes dst surface was allocated with the correct dimensions.
 
738
 
 
739
\param src Source surface.
 
740
\param dst Destination surface.
 
741
\param cx Horizontal center coordinate.
 
742
\param cy Vertical center coordinate.
 
743
\param isin Integer version of sine of angle.
 
744
\param icos Integer version of cosine of angle.
 
745
\param flipx Flag indicating horizontal mirroring should be applied.
 
746
\param flipy Flag indicating vertical mirroring should be applied.
 
747
*/
 
748
void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
 
749
{
 
750
        int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
 
751
        tColorY *pc, *sp;
 
752
        int gap;
 
753
 
 
754
        /*
 
755
        * Variable setup 
 
756
        */
 
757
        xd = ((src->w - dst->w) << 15);
 
758
        yd = ((src->h - dst->h) << 15);
 
759
        ax = (cx << 16) - (icos * cx);
 
760
        ay = (cy << 16) - (isin * cx);
 
761
        sw = src->w - 1;
 
762
        sh = src->h - 1;
 
763
        pc = (tColorY*) dst->pixels;
 
764
        gap = dst->pitch - dst->w;
 
765
        /*
 
766
        * Clear surface to colorkey 
 
767
        */      
 
768
        memset(pc, (int)(_colorkey(src) & 0xff), dst->pitch * dst->h);
 
769
        /*
 
770
        * Iterate through destination surface 
 
771
        */
 
772
        for (y = 0; y < dst->h; y++) {
 
773
                dy = cy - y;
 
774
                sdx = (ax + (isin * dy)) + xd;
 
775
                sdy = (ay - (icos * dy)) + yd;
 
776
                for (x = 0; x < dst->w; x++) {
 
777
                        dx = (short) (sdx >> 16);
 
778
                        dy = (short) (sdy >> 16);
 
779
                        if (flipx) dx = (src->w-1)-dx;
 
780
                        if (flipy) dy = (src->h-1)-dy;
 
781
                        if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
 
782
                                sp = (tColorY *) (src->pixels);
 
783
                                sp += (src->pitch * dy + dx);
 
784
                                *pc = *sp;
 
785
                        }
 
786
                        sdx += icos;
 
787
                        sdy += isin;
 
788
                        pc++;
 
789
                }
 
790
                pc += gap;
 
791
        }
 
792
}
 
793
 
 
794
/*!
 
795
\brief Rotates a 32 bit surface in increments of 90 degrees.
 
796
 
 
797
Specialized 90 degree rotator which rotates a 'src' surface in 90 degree 
 
798
increments clockwise returning a new surface. Faster than rotozoomer since
 
799
not scanning or interpolation takes place. Input surface must be 32 bit.
 
800
(code contributed by J. Schiller, improved by C. Allport and A. Schiffler)
 
801
 
 
802
\param src Source surface to rotate.
 
803
\param numClockwiseTurns Number of clockwise 90 degree turns to apply to the source.
 
804
 
 
805
\returns The new, rotated surface; or NULL for surfaces with incorrect input format.
 
806
*/
 
807
SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns) 
 
808
{
 
809
        int row, col, newWidth, newHeight;
 
810
        int bpp, src_ipr, dst_ipr;
 
811
        SDL_Surface* dst;
 
812
        Uint32* srcBuf;
 
813
        Uint32* dstBuf;
 
814
 
 
815
        /* Has to be a valid surface pointer and only 32-bit surfaces (for now) */
 
816
        if (!src || src->format->BitsPerPixel != 32) { return NULL; }
 
817
 
 
818
        /* normalize numClockwiseTurns */
 
819
        while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
 
820
        numClockwiseTurns = (numClockwiseTurns % 4);
 
821
 
 
822
        /* if it's even, our new width will be the same as the source surface */
 
823
        newWidth = (numClockwiseTurns % 2) ? (src->h) : (src->w);
 
824
        newHeight = (numClockwiseTurns % 2) ? (src->w) : (src->h);
 
825
        dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel,
 
826
                src->format->Rmask,
 
827
                src->format->Gmask, 
 
828
                src->format->Bmask, 
 
829
                src->format->Amask);
 
830
        if(!dst) {
 
831
                return NULL;
 
832
        }
 
833
 
 
834
        if (SDL_MUSTLOCK(dst)) {
 
835
                SDL_LockSurface(dst);
 
836
        }
 
837
        if (SDL_MUSTLOCK(dst)) {
 
838
                SDL_LockSurface(dst);
 
839
        }
 
840
 
 
841
        /* Calculate int-per-row */
 
842
        bpp = src->format->BitsPerPixel / 8;
 
843
        src_ipr = src->pitch / bpp;
 
844
        dst_ipr = dst->pitch / bpp;
 
845
 
 
846
        switch(numClockwiseTurns) {
 
847
        case 0: /* Make a copy of the surface */
 
848
                {
 
849
                        /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
 
850
                        since it does not preserve alpha. */
 
851
 
 
852
                        if (src->pitch == dst->pitch) {
 
853
                                /* If the pitch is the same for both surfaces, the memory can be copied all at once. */
 
854
                                memcpy(dst->pixels, src->pixels, (src->h * src->pitch));
 
855
                        }
 
856
                        else
 
857
                        {
 
858
                                /* If the pitch differs, copy each row separately */
 
859
                                srcBuf = (Uint32*)(src->pixels); 
 
860
                                dstBuf = (Uint32*)(dst->pixels);
 
861
                                for (row = 0; row < src->h; row++) {
 
862
                                        memcpy(dstBuf, srcBuf, dst->w * bpp);
 
863
                                        srcBuf += src_ipr;
 
864
                                        dstBuf += dst_ipr;
 
865
                                } /* end for(col) */
 
866
                        } /* end for(row) */
 
867
                }
 
868
                break;
 
869
 
 
870
                /* rotate clockwise */
 
871
        case 1: /* rotated 90 degrees clockwise */
 
872
                {
 
873
                        for (row = 0; row < src->h; ++row) {
 
874
                                srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
 
875
                                dstBuf = (Uint32*)(dst->pixels) + (dst->w - row - 1);
 
876
                                for (col = 0; col < src->w; ++col) {
 
877
                                        *dstBuf = *srcBuf;
 
878
                                        ++srcBuf;
 
879
                                        dstBuf += dst_ipr;
 
880
                                } 
 
881
                                /* end for(col) */
 
882
                        } 
 
883
                        /* end for(row) */
 
884
                }
 
885
                break;
 
886
 
 
887
        case 2: /* rotated 180 degrees clockwise */
 
888
                {
 
889
                        for (row = 0; row < src->h; ++row) {
 
890
                                srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
 
891
                                dstBuf = (Uint32*)(dst->pixels) + ((dst->h - row - 1) * dst_ipr) + (dst->w - 1);
 
892
                                for (col = 0; col < src->w; ++col) {
 
893
                                        *dstBuf = *srcBuf;
 
894
                                        ++srcBuf;
 
895
                                        --dstBuf;
 
896
                                } 
 
897
                        } 
 
898
                }
 
899
                break;
 
900
 
 
901
        case 3:
 
902
                {
 
903
                        for (row = 0; row < src->h; ++row) {
 
904
                                srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
 
905
                                dstBuf = (Uint32*)(dst->pixels) + row + ((dst->h - 1) * dst_ipr);
 
906
                                for (col = 0; col < src->w; ++col) {
 
907
                                        *dstBuf = *srcBuf;
 
908
                                        ++srcBuf;
 
909
                                        dstBuf -= dst_ipr;
 
910
                                } 
 
911
                        } 
 
912
                }
 
913
                break;
 
914
        } 
 
915
        /* end switch */
 
916
 
 
917
        if (SDL_MUSTLOCK(src)) {
 
918
                SDL_UnlockSurface(src);
 
919
        }
 
920
        if (SDL_MUSTLOCK(dst)) {
 
921
                SDL_UnlockSurface(dst);
 
922
        }
 
923
 
 
924
        return dst;
 
925
}
 
926
 
 
927
 
 
928
/*!
 
929
\brief Internal target surface sizing function for rotozooms with trig result return. 
 
930
 
 
931
\param width The source surface width.
 
932
\param height The source surface height.
 
933
\param angle The angle to rotate in degrees.
 
934
\param zoomx The horizontal scaling factor.
 
935
\param zoomy The vertical scaling factor.
 
936
\param dstwidth The calculated width of the destination surface.
 
937
\param dstheight The calculated height of the destination surface.
 
938
\param canglezoom The sine of the angle adjusted by the zoom factor.
 
939
\param sanglezoom The cosine of the angle adjusted by the zoom factor.
 
940
 
 
941
*/
 
942
void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy, 
 
943
        int *dstwidth, int *dstheight, 
 
944
        double *canglezoom, double *sanglezoom)
 
945
{
 
946
        double x, y, cx, cy, sx, sy;
 
947
        double radangle;
 
948
        int dstwidthhalf, dstheighthalf;
 
949
 
 
950
        /*
 
951
        * Determine destination width and height by rotating a centered source box 
 
952
        */
 
953
        radangle = angle * (M_PI / 180.0);
 
954
        *sanglezoom = sin(radangle);
 
955
        *canglezoom = cos(radangle);
 
956
        *sanglezoom *= zoomx;
 
957
        *canglezoom *= zoomx;
 
958
        x = (double)(width / 2);
 
959
        y = (double)(height / 2);
 
960
        cx = *canglezoom * x;
 
961
        cy = *canglezoom * y;
 
962
        sx = *sanglezoom * x;
 
963
        sy = *sanglezoom * y;
 
964
 
 
965
        dstwidthhalf = MAX((int)
 
966
                ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
 
967
        dstheighthalf = MAX((int)
 
968
                ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
 
969
        *dstwidth = 2 * dstwidthhalf;
 
970
        *dstheight = 2 * dstheighthalf;
 
971
}
 
972
 
 
973
/*! 
 
974
\brief Returns the size of the resulting target surface for a rotozoomSurfaceXY() call. 
 
975
 
 
976
\param width The source surface width.
 
977
\param height The source surface height.
 
978
\param angle The angle to rotate in degrees.
 
979
\param zoomx The horizontal scaling factor.
 
980
\param zoomy The vertical scaling factor.
 
981
\param dstwidth The calculated width of the rotozoomed destination surface.
 
982
\param dstheight The calculated height of the rotozoomed destination surface.
 
983
*/
 
984
void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
 
985
{
 
986
        double dummy_sanglezoom, dummy_canglezoom;
 
987
 
 
988
        _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
 
989
}
 
990
 
 
991
/*! 
 
992
\brief Returns the size of the resulting target surface for a rotozoomSurface() call. 
 
993
 
 
994
\param width The source surface width.
 
995
\param height The source surface height.
 
996
\param angle The angle to rotate in degrees.
 
997
\param zoom The scaling factor.
 
998
\param dstwidth The calculated width of the rotozoomed destination surface.
 
999
\param dstheight The calculated height of the rotozoomed destination surface.
 
1000
*/
 
1001
void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
 
1002
{
 
1003
        double dummy_sanglezoom, dummy_canglezoom;
 
1004
 
 
1005
        _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
 
1006
}
 
1007
 
 
1008
/*!
 
1009
\brief Rotates and zooms a surface and optional anti-aliasing. 
 
1010
 
 
1011
Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
 
1012
'angle' is the rotation in degrees and 'zoom' a scaling factor. If 'smooth' is set
 
1013
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
 
1014
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
 
1015
 
 
1016
\param src The surface to rotozoom.
 
1017
\param angle The angle to rotate in degrees.
 
1018
\param zoom The scaling factor.
 
1019
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
 
1020
 
 
1021
\return The new rotozoomed surface.
 
1022
*/
 
1023
SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
 
1024
{
 
1025
        return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
 
1026
}
 
1027
 
 
1028
/*!
 
1029
\brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing. 
 
1030
 
 
1031
Rotates and zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
 
1032
'angle' is the rotation in degrees, 'zoomx and 'zoomy' scaling factors. If 'smooth' is set
 
1033
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
 
1034
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
 
1035
 
 
1036
\param src The surface to rotozoom.
 
1037
\param angle The angle to rotate in degrees.
 
1038
\param zoomx The horizontal scaling factor.
 
1039
\param zoomy The vertical scaling factor.
 
1040
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
 
1041
 
 
1042
\return The new rotozoomed surface.
 
1043
*/
 
1044
SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
 
1045
{
 
1046
        SDL_Surface *rz_src;
 
1047
        SDL_Surface *rz_dst;
 
1048
        double zoominv;
 
1049
        double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
 
1050
        int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
 
1051
        int is32bit;
 
1052
        int i, src_converted;
 
1053
        int flipx,flipy;
 
1054
 
 
1055
        /*
 
1056
        * Sanity check 
 
1057
        */
 
1058
        if (src == NULL) {
 
1059
                return (NULL);
 
1060
        }
 
1061
 
 
1062
        /*
 
1063
        * Determine if source surface is 32bit or 8bit 
 
1064
        */
 
1065
        is32bit = (src->format->BitsPerPixel == 32);
 
1066
        if ((is32bit) || (src->format->BitsPerPixel == 8)) {
 
1067
                /*
 
1068
                * Use source surface 'as is' 
 
1069
                */
 
1070
                rz_src = src;
 
1071
                src_converted = 0;
 
1072
        } else {
 
1073
                /*
 
1074
                * New source surface is 32bit with a defined RGBA ordering 
 
1075
                */
 
1076
                rz_src =
 
1077
                        SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
 
1078
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
 
1079
                        0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
 
1080
#else
 
1081
                        0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
 
1082
#endif
 
1083
                        );
 
1084
 
 
1085
                SDL_BlitSurface(src, NULL, rz_src, NULL);
 
1086
 
 
1087
                src_converted = 1;
 
1088
                is32bit = 1;
 
1089
        }
 
1090
 
 
1091
        /*
 
1092
        * Sanity check zoom factor 
 
1093
        */
 
1094
        flipx = (zoomx<0.0);
 
1095
        if (flipx) zoomx=-zoomx;
 
1096
        flipy = (zoomy<0.0);
 
1097
        if (flipy) zoomy=-zoomy;
 
1098
        if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
 
1099
        if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
 
1100
        zoominv = 65536.0 / (zoomx * zoomx);
 
1101
 
 
1102
        /*
 
1103
        * Check if we have a rotozoom or just a zoom 
 
1104
        */
 
1105
        if (fabs(angle) > VALUE_LIMIT) {
 
1106
 
 
1107
                /*
 
1108
                * Angle!=0: full rotozoom 
 
1109
                */
 
1110
                /*
 
1111
                * ----------------------- 
 
1112
                */
 
1113
 
 
1114
                /* Determine target size */
 
1115
                _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
 
1116
 
 
1117
                /*
 
1118
                * Calculate target factors from sin/cos and zoom 
 
1119
                */
 
1120
                sanglezoominv = sanglezoom;
 
1121
                canglezoominv = canglezoom;
 
1122
                sanglezoominv *= zoominv;
 
1123
                canglezoominv *= zoominv;
 
1124
 
 
1125
                /* Calculate half size */
 
1126
                dstwidthhalf = dstwidth / 2;
 
1127
                dstheighthalf = dstheight / 2;
 
1128
 
 
1129
                /*
 
1130
                * Alloc space to completely contain the rotated surface 
 
1131
                */
 
1132
                rz_dst = NULL;
 
1133
                if (is32bit) {
 
1134
                        /*
 
1135
                        * Target surface is 32bit with source RGBA/ABGR ordering 
 
1136
                        */
 
1137
                        rz_dst =
 
1138
                                SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
 
1139
                                rz_src->format->Rmask, rz_src->format->Gmask,
 
1140
                                rz_src->format->Bmask, rz_src->format->Amask);
 
1141
                } else {
 
1142
                        /*
 
1143
                        * Target surface is 8bit 
 
1144
                        */
 
1145
                        rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
 
1146
                }
 
1147
 
 
1148
                /* Check target */
 
1149
                if (rz_dst == NULL)
 
1150
                        return NULL;
 
1151
 
 
1152
                /* Adjust for guard rows */
 
1153
                rz_dst->h = dstheight;
 
1154
 
 
1155
                /*
 
1156
                * Lock source surface 
 
1157
                */
 
1158
                if (SDL_MUSTLOCK(rz_src)) {
 
1159
                        SDL_LockSurface(rz_src);
 
1160
                }
 
1161
 
 
1162
                /*
 
1163
                * Check which kind of surface we have 
 
1164
                */
 
1165
                if (is32bit) {
 
1166
                        /*
 
1167
                        * Call the 32bit transformation routine to do the rotation (using alpha) 
 
1168
                        */
 
1169
                        _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
 
1170
                                (int) (sanglezoominv), (int) (canglezoominv), 
 
1171
                                flipx, flipy,
 
1172
                                smooth);
 
1173
                } else {
 
1174
                        /*
 
1175
                        * Copy palette and colorkey info 
 
1176
                        */
 
1177
                        for (i = 0; i < rz_src->format->palette->ncolors; i++) {
 
1178
                                rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
 
1179
                        }
 
1180
                        rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
 
1181
                        /*
 
1182
                        * Call the 8bit transformation routine to do the rotation 
 
1183
                        */
 
1184
                        transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
 
1185
                                (int) (sanglezoominv), (int) (canglezoominv),
 
1186
                                flipx, flipy);
 
1187
                }
 
1188
                /*
 
1189
                * Unlock source surface 
 
1190
                */
 
1191
                if (SDL_MUSTLOCK(rz_src)) {
 
1192
                        SDL_UnlockSurface(rz_src);
 
1193
                }
 
1194
 
 
1195
        } else {
 
1196
 
 
1197
                /*
 
1198
                * Angle=0: Just a zoom 
 
1199
                */
 
1200
                /*
 
1201
                * -------------------- 
 
1202
                */
 
1203
 
 
1204
                /*
 
1205
                * Calculate target size
 
1206
                */
 
1207
                zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
 
1208
 
 
1209
                /*
 
1210
                * Alloc space to completely contain the zoomed surface 
 
1211
                */
 
1212
                rz_dst = NULL;
 
1213
                if (is32bit) {
 
1214
                        /*
 
1215
                        * Target surface is 32bit with source RGBA/ABGR ordering 
 
1216
                        */
 
1217
                        rz_dst =
 
1218
                                SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
 
1219
                                rz_src->format->Rmask, rz_src->format->Gmask,
 
1220
                                rz_src->format->Bmask, rz_src->format->Amask);
 
1221
                } else {
 
1222
                        /*
 
1223
                        * Target surface is 8bit 
 
1224
                        */
 
1225
                        rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
 
1226
                }
 
1227
 
 
1228
                /* Check target */
 
1229
                if (rz_dst == NULL)
 
1230
                        return NULL;
 
1231
 
 
1232
                /* Adjust for guard rows */
 
1233
                rz_dst->h = dstheight;
 
1234
 
 
1235
                /*
 
1236
                * Lock source surface 
 
1237
                */
 
1238
                if (SDL_MUSTLOCK(rz_src)) {
 
1239
                        SDL_LockSurface(rz_src);
 
1240
                }
 
1241
 
 
1242
                /*
 
1243
                * Check which kind of surface we have 
 
1244
                */
 
1245
                if (is32bit) {
 
1246
                        /*
 
1247
                        * Call the 32bit transformation routine to do the zooming (using alpha) 
 
1248
                        */
 
1249
                        _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
 
1250
 
 
1251
                } else {
 
1252
                        /*
 
1253
                        * Copy palette and colorkey info 
 
1254
                        */
 
1255
                        for (i = 0; i < rz_src->format->palette->ncolors; i++) {
 
1256
                                rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
 
1257
                        }
 
1258
                        rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
 
1259
 
 
1260
                        /*
 
1261
                        * Call the 8bit transformation routine to do the zooming 
 
1262
                        */
 
1263
                        _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
 
1264
                }
 
1265
 
 
1266
                /*
 
1267
                * Unlock source surface 
 
1268
                */
 
1269
                if (SDL_MUSTLOCK(rz_src)) {
 
1270
                        SDL_UnlockSurface(rz_src);
 
1271
                }
 
1272
        }
 
1273
 
 
1274
        /*
 
1275
        * Cleanup temp surface 
 
1276
        */
 
1277
        if (src_converted) {
 
1278
                SDL_FreeSurface(rz_src);
 
1279
        }
 
1280
 
 
1281
        /*
 
1282
        * Return destination surface 
 
1283
        */
 
1284
        return (rz_dst);
 
1285
}
 
1286
 
 
1287
/*!
 
1288
\brief Calculates the size of the target surface for a zoomSurface() call.
 
1289
 
 
1290
The minimum size of the target surface is 1. The input factors can be positive or negative.
 
1291
 
 
1292
\param width The width of the source surface to zoom.
 
1293
\param height The height of the source surface to zoom.
 
1294
\param zoomx The horizontal zoom factor.
 
1295
\param zoomy The vertical zoom factor.
 
1296
\param dstwidth Pointer to an integer to store the calculated width of the zoomed target surface.
 
1297
\param dstheight Pointer to an integer to store the calculated height of the zoomed target surface.
 
1298
*/
 
1299
void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
 
1300
{
 
1301
        /*
 
1302
        * Make zoom factors positive 
 
1303
        */
 
1304
        int flipx, flipy;
 
1305
        flipx = (zoomx<0.0);
 
1306
        if (flipx) zoomx = -zoomx;
 
1307
        flipy = (zoomy<0.0);
 
1308
        if (flipy) zoomy = -zoomy;
 
1309
 
 
1310
        /*
 
1311
        * Sanity check zoom factors 
 
1312
        */
 
1313
        if (zoomx < VALUE_LIMIT) {
 
1314
                zoomx = VALUE_LIMIT;
 
1315
        }
 
1316
        if (zoomy < VALUE_LIMIT) {
 
1317
                zoomy = VALUE_LIMIT;
 
1318
        }
 
1319
 
 
1320
        /*
 
1321
        * Calculate target size 
 
1322
        */
 
1323
        *dstwidth = (int) floor(((double) width * zoomx) + 0.5);
 
1324
        *dstheight = (int) floor(((double) height * zoomy) + 0.5);
 
1325
        if (*dstwidth < 1) {
 
1326
                *dstwidth = 1;
 
1327
        }
 
1328
        if (*dstheight < 1) {
 
1329
                *dstheight = 1;
 
1330
        }
 
1331
}
 
1332
 
 
1333
/*! 
 
1334
\brief Zoom a surface by independent horizontal and vertical factors with optional smoothing.
 
1335
 
 
1336
Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
 
1337
'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is on
 
1338
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
 
1339
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
 
1340
If zoom factors are negative, the image is flipped on the axes.
 
1341
 
 
1342
\param src The surface to zoom.
 
1343
\param zoomx The horizontal zoom factor.
 
1344
\param zoomy The vertical zoom factor.
 
1345
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
 
1346
 
 
1347
\return The new, zoomed surface.
 
1348
*/
 
1349
SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
 
1350
{
 
1351
        SDL_Surface *rz_src;
 
1352
        SDL_Surface *rz_dst;
 
1353
        int dstwidth, dstheight;
 
1354
        int is32bit;
 
1355
        int i, src_converted;
 
1356
        int flipx, flipy;
 
1357
 
 
1358
        /*
 
1359
        * Sanity check 
 
1360
        */
 
1361
        if (src == NULL)
 
1362
                return (NULL);
 
1363
 
 
1364
        /*
 
1365
        * Determine if source surface is 32bit or 8bit 
 
1366
        */
 
1367
        is32bit = (src->format->BitsPerPixel == 32);
 
1368
        if ((is32bit) || (src->format->BitsPerPixel == 8)) {
 
1369
                /*
 
1370
                * Use source surface 'as is' 
 
1371
                */
 
1372
                rz_src = src;
 
1373
                src_converted = 0;
 
1374
        } else {
 
1375
                /*
 
1376
                * New source surface is 32bit with a defined RGBA ordering 
 
1377
                */
 
1378
                rz_src =
 
1379
                        SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
 
1380
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
 
1381
                        0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
 
1382
#else
 
1383
                        0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
 
1384
#endif
 
1385
                        );
 
1386
                if (rz_src == NULL) {
 
1387
                        return NULL;
 
1388
                }
 
1389
                SDL_BlitSurface(src, NULL, rz_src, NULL);
 
1390
                src_converted = 1;
 
1391
                is32bit = 1;
 
1392
        }
 
1393
 
 
1394
        flipx = (zoomx<0.0);
 
1395
        if (flipx) zoomx = -zoomx;
 
1396
        flipy = (zoomy<0.0);
 
1397
        if (flipy) zoomy = -zoomy;
 
1398
 
 
1399
        /* Get size if target */
 
1400
        zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
 
1401
 
 
1402
        /*
 
1403
        * Alloc space to completely contain the zoomed surface 
 
1404
        */
 
1405
        rz_dst = NULL;
 
1406
        if (is32bit) {
 
1407
                /*
 
1408
                * Target surface is 32bit with source RGBA/ABGR ordering 
 
1409
                */
 
1410
                rz_dst =
 
1411
                        SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
 
1412
                        rz_src->format->Rmask, rz_src->format->Gmask,
 
1413
                        rz_src->format->Bmask, rz_src->format->Amask);
 
1414
        } else {
 
1415
                /*
 
1416
                * Target surface is 8bit 
 
1417
                */
 
1418
                rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
 
1419
        }
 
1420
 
 
1421
        /* Check target */
 
1422
        if (rz_dst == NULL) {
 
1423
                /*
 
1424
                * Cleanup temp surface 
 
1425
                */
 
1426
                if (src_converted) {
 
1427
                        SDL_FreeSurface(rz_src);
 
1428
                }               
 
1429
                return NULL;
 
1430
        }
 
1431
 
 
1432
        /* Adjust for guard rows */
 
1433
        rz_dst->h = dstheight;
 
1434
 
 
1435
        /*
 
1436
        * Lock source surface 
 
1437
        */
 
1438
        if (SDL_MUSTLOCK(rz_src)) {
 
1439
                SDL_LockSurface(rz_src);
 
1440
        }
 
1441
 
 
1442
        /*
 
1443
        * Check which kind of surface we have 
 
1444
        */
 
1445
        if (is32bit) {
 
1446
                /*
 
1447
                * Call the 32bit transformation routine to do the zooming (using alpha) 
 
1448
                */
 
1449
                _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
 
1450
        } else {
 
1451
                /*
 
1452
                * Copy palette and colorkey info 
 
1453
                */
 
1454
                for (i = 0; i < rz_src->format->palette->ncolors; i++) {
 
1455
                        rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
 
1456
                }
 
1457
                rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
 
1458
                /*
 
1459
                * Call the 8bit transformation routine to do the zooming 
 
1460
                */
 
1461
                _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
 
1462
        }
 
1463
        /*
 
1464
        * Unlock source surface 
 
1465
        */
 
1466
        if (SDL_MUSTLOCK(rz_src)) {
 
1467
                SDL_UnlockSurface(rz_src);
 
1468
        }
 
1469
 
 
1470
        /*
 
1471
        * Cleanup temp surface 
 
1472
        */
 
1473
        if (src_converted) {
 
1474
                SDL_FreeSurface(rz_src);
 
1475
        }
 
1476
 
 
1477
        /*
 
1478
        * Return destination surface 
 
1479
        */
 
1480
        return (rz_dst);
 
1481
}
 
1482
 
 
1483
/*! 
 
1484
\brief Shrink a surface by an integer ratio using averaging.
 
1485
 
 
1486
Shrinks a 32bit or 8bit 'src' surface to a newly created 'dst' surface.
 
1487
'factorx' and 'factory' are the shrinking ratios (i.e. 2=1/2 the size,
 
1488
3=1/3 the size, etc.) The destination surface is antialiased by averaging
 
1489
the source box RGBA or Y information. If the surface is not 8bit
 
1490
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
 
1491
The input surface is not modified. The output surface is newly allocated.
 
1492
 
 
1493
\param src The surface to shrink.
 
1494
\param factorx The horizontal shrinking ratio.
 
1495
\param factory The vertical shrinking ratio.
 
1496
 
 
1497
\return The new, shrunken surface.
 
1498
*/
 
1499
/*@null@*/ 
 
1500
SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
 
1501
{
 
1502
        int result;
 
1503
        SDL_Surface *rz_src;
 
1504
        SDL_Surface *rz_dst = NULL;
 
1505
        int dstwidth, dstheight;
 
1506
        int is32bit;
 
1507
        int i, src_converted;
 
1508
        int haveError = 0;
 
1509
 
 
1510
        /*
 
1511
        * Sanity check 
 
1512
        */
 
1513
        if (src == NULL) {
 
1514
                return (NULL);
 
1515
        }
 
1516
 
 
1517
        /*
 
1518
        * Determine if source surface is 32bit or 8bit 
 
1519
        */
 
1520
        is32bit = (src->format->BitsPerPixel == 32);
 
1521
        if ((is32bit) || (src->format->BitsPerPixel == 8)) {
 
1522
                /*
 
1523
                * Use source surface 'as is' 
 
1524
                */
 
1525
                rz_src = src;
 
1526
                src_converted = 0;
 
1527
        } else {
 
1528
                /*
 
1529
                * New source surface is 32bit with a defined RGBA ordering 
 
1530
                */
 
1531
                rz_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 
 
1532
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
 
1533
                        0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
 
1534
#else
 
1535
                        0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
 
1536
#endif
 
1537
                        );
 
1538
                if (rz_src==NULL) {
 
1539
                        haveError = 1;
 
1540
                        goto exitShrinkSurface;
 
1541
                }
 
1542
 
 
1543
                SDL_BlitSurface(src, NULL, rz_src, NULL);
 
1544
                src_converted = 1;
 
1545
                is32bit = 1;
 
1546
        }
 
1547
 
 
1548
        /*
 
1549
        * Lock the surface 
 
1550
        */
 
1551
        if (SDL_MUSTLOCK(rz_src)) {
 
1552
                if (SDL_LockSurface(rz_src) < 0) {
 
1553
                        haveError = 1;
 
1554
                        goto exitShrinkSurface;
 
1555
                }
 
1556
        }
 
1557
 
 
1558
        /* Get size for target */
 
1559
        dstwidth=rz_src->w/factorx;
 
1560
        while (dstwidth*factorx>rz_src->w) { dstwidth--; }
 
1561
        dstheight=rz_src->h/factory;
 
1562
        while (dstheight*factory>rz_src->h) { dstheight--; }
 
1563
 
 
1564
        /*
 
1565
        * Alloc space to completely contain the shrunken surface
 
1566
        * (with added guard rows)
 
1567
        */
 
1568
        if (is32bit==1) {
 
1569
                /*
 
1570
                * Target surface is 32bit with source RGBA/ABGR ordering 
 
1571
                */
 
1572
                rz_dst =
 
1573
                        SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
 
1574
                        rz_src->format->Rmask, rz_src->format->Gmask,
 
1575
                        rz_src->format->Bmask, rz_src->format->Amask);
 
1576
        } else {
 
1577
                /*
 
1578
                * Target surface is 8bit 
 
1579
                */
 
1580
                rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
 
1581
        }
 
1582
 
 
1583
        /* Check target */
 
1584
        if (rz_dst == NULL) {
 
1585
                haveError = 1;
 
1586
                goto exitShrinkSurface;
 
1587
        }
 
1588
 
 
1589
        /* Adjust for guard rows */
 
1590
        rz_dst->h = dstheight;
 
1591
 
 
1592
        /*
 
1593
        * Check which kind of surface we have 
 
1594
        */
 
1595
        if (is32bit==1) {
 
1596
                /*
 
1597
                * Call the 32bit transformation routine to do the shrinking (using alpha) 
 
1598
                */
 
1599
                result = _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);          
 
1600
                if ((result!=0) || (rz_dst==NULL)) {
 
1601
                        haveError = 1;
 
1602
                        goto exitShrinkSurface;
 
1603
                }
 
1604
        } else {
 
1605
                /*
 
1606
                * Copy palette and colorkey info 
 
1607
                */
 
1608
                for (i = 0; i < rz_src->format->palette->ncolors; i++) {
 
1609
                        rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
 
1610
                }
 
1611
                rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
 
1612
                /*
 
1613
                * Call the 8bit transformation routine to do the shrinking 
 
1614
                */
 
1615
                result = _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
 
1616
                if (result!=0) {
 
1617
                        haveError = 1;
 
1618
                        goto exitShrinkSurface;
 
1619
                }
 
1620
        }
 
1621
 
 
1622
exitShrinkSurface:
 
1623
        if (rz_src!=NULL) {
 
1624
                /*
 
1625
                * Unlock source surface 
 
1626
                */
 
1627
                if (SDL_MUSTLOCK(rz_src)) {
 
1628
                        SDL_UnlockSurface(rz_src);
 
1629
                }
 
1630
 
 
1631
                /*
 
1632
                * Cleanup temp surface 
 
1633
                */
 
1634
                if (src_converted==1) {
 
1635
                        SDL_FreeSurface(rz_src);
 
1636
                }
 
1637
        }
 
1638
 
 
1639
        /* Check error state; maybe need to cleanup destination */
 
1640
        if (haveError==1) {
 
1641
                if (rz_dst!=NULL) {
 
1642
                        SDL_FreeSurface(rz_dst);
 
1643
                }
 
1644
                rz_dst=NULL;
 
1645
        } 
 
1646
 
 
1647
        /*
 
1648
        * Return destination surface 
 
1649
        */
 
1650
        return (rz_dst);
 
1651
}