1 /* Copyright (C) 2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12 #include "android/skin/scaler.h"
13 #include <stdint.h>
14 #include <math.h>
15
16 struct SkinScaler {
17 double scale;
18 double xdisp, ydisp;
19 double invscale;
20 int valid;
21 };
22
23 static SkinScaler _scaler0;
24
25 SkinScaler*
skin_scaler_create(void)26 skin_scaler_create( void )
27 {
28 _scaler0.scale = 1.0;
29 _scaler0.xdisp = 0.0;
30 _scaler0.ydisp = 0.0;
31 _scaler0.invscale = 1.0;
32 return &_scaler0;
33 }
34
35 /* change the scale of a given scaler. returns 0 on success, or -1 in case of
36 * problem (unsupported scale) */
37 int
skin_scaler_set(SkinScaler * scaler,double scale,double xdisp,double ydisp)38 skin_scaler_set( SkinScaler* scaler, double scale, double xdisp, double ydisp )
39 {
40 /* right now, we only support scales in the 0.5 .. 1.0 range */
41 if (scale < 0.1)
42 scale = 0.1;
43 else if (scale > 6.0)
44 scale = 6.0;
45
46 scaler->scale = scale;
47 scaler->xdisp = xdisp;
48 scaler->ydisp = ydisp;
49 scaler->invscale = 1/scale;
50 scaler->valid = 1;
51
52 return 0;
53 }
54
55 void
skin_scaler_free(SkinScaler * scaler)56 skin_scaler_free( SkinScaler* scaler )
57 {
58 scaler=scaler;
59 }
60
61 typedef struct {
62 SDL_Rect rd; /* destination rectangle */
63 int sx, sy; /* source start position in 16.16 format */
64 int ix, iy; /* source increments in 16.16 format */
65 int src_pitch;
66 int src_w;
67 int src_h;
68 int dst_pitch;
69 uint8_t* dst_line;
70 uint8_t* src_line;
71 double scale;
72 } ScaleOp;
73
74
75 #define ARGB_SCALE_GENERIC scale_generic
76 #define ARGB_SCALE_05_TO_10 scale_05_to_10
77 #define ARGB_SCALE_UP_BILINEAR scale_up_bilinear
78 /* #define ARGB_SCALE_UP_QUICK_4x4 scale_up_quick_4x4 UNUSED */
79
80 #include "android/skin/argb.h"
81
82
83 void
skin_scaler_get_scaled_rect(SkinScaler * scaler,SkinRect * srect,SkinRect * drect)84 skin_scaler_get_scaled_rect( SkinScaler* scaler,
85 SkinRect* srect,
86 SkinRect* drect )
87 {
88 int sx = srect->pos.x;
89 int sy = srect->pos.y;
90 int sw = srect->size.w;
91 int sh = srect->size.h;
92 double scale = scaler->scale;
93
94 if (!scaler->valid) {
95 drect[0] = srect[0];
96 return;
97 }
98
99 drect->pos.x = (int)(sx * scale + scaler->xdisp);
100 drect->pos.y = (int)(sy * scale + scaler->ydisp);
101 drect->size.w = (int)(ceil((sx + sw) * scale + scaler->xdisp)) - drect->pos.x;
102 drect->size.h = (int)(ceil((sy + sh) * scale + scaler->ydisp)) - drect->pos.y;
103 }
104
105 void
skin_scaler_scale(SkinScaler * scaler,SDL_Surface * dst_surface,SDL_Surface * src_surface,int sx,int sy,int sw,int sh)106 skin_scaler_scale( SkinScaler* scaler,
107 SDL_Surface* dst_surface,
108 SDL_Surface* src_surface,
109 int sx,
110 int sy,
111 int sw,
112 int sh )
113 {
114 ScaleOp op;
115
116 if ( !scaler->valid )
117 return;
118
119 SDL_LockSurface( src_surface );
120 SDL_LockSurface( dst_surface );
121 {
122 op.scale = scaler->scale;
123 op.src_pitch = src_surface->pitch;
124 op.src_line = src_surface->pixels;
125 op.src_w = src_surface->w;
126 op.src_h = src_surface->h;
127 op.dst_pitch = dst_surface->pitch;
128 op.dst_line = dst_surface->pixels;
129
130 /* compute the destination rectangle */
131 op.rd.x = (int)(sx * scaler->scale + scaler->xdisp);
132 op.rd.y = (int)(sy * scaler->scale + scaler->ydisp);
133 op.rd.w = (int)(ceil((sx + sw) * scaler->scale + scaler->xdisp)) - op.rd.x;
134 op.rd.h = (int)(ceil((sy + sh) * scaler->scale + scaler->ydisp)) - op.rd.y;
135
136 /* compute the starting source position in 16.16 format
137 * and the corresponding increments */
138 op.sx = (int)((op.rd.x - scaler->xdisp) * scaler->invscale * 65536);
139 op.sy = (int)((op.rd.y - scaler->ydisp) * scaler->invscale * 65536);
140
141 op.ix = (int)( scaler->invscale * 65536 );
142 op.iy = op.ix;
143
144 op.dst_line += op.rd.x*4 + op.rd.y*op.dst_pitch;
145
146 if (op.scale >= 0.5 && op.scale <= 1.0)
147 scale_05_to_10( &op );
148 else if (op.scale > 1.0)
149 scale_up_bilinear( &op );
150 else
151 scale_generic( &op );
152 }
153 SDL_UnlockSurface( dst_surface );
154 SDL_UnlockSurface( src_surface );
155
156 SDL_UpdateRects( dst_surface, 1, &op.rd );
157 }
158