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* 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 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 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 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 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 154 // The optimized scale functions in argb.h assume the destination is ARGB. 155 // If that's not the case, do a channel reorder now. 156 if (dst_surface->format->Rshift != 16 || 157 dst_surface->format->Gshift != 8 || 158 dst_surface->format->Bshift != 0) 159 { 160 uint32_t rshift = dst_surface->format->Rshift; 161 uint32_t gshift = dst_surface->format->Gshift; 162 uint32_t bshift = dst_surface->format->Bshift; 163 uint32_t ashift = dst_surface->format->Ashift; 164 uint32_t amask = dst_surface->format->Amask; // may be 0x00 165 int x, y; 166 167 for (y = 0; y < op.rd.h; y++) 168 { 169 uint32_t* line = (uint32_t*)(op.dst_line + y*op.dst_pitch); 170 for (x = 0; x < op.rd.w; x++) { 171 uint32_t r = (line[x] & 0x00ff0000) >> 16; 172 uint32_t g = (line[x] & 0x0000ff00) >> 8; 173 uint32_t b = (line[x] & 0x000000ff) >> 0; 174 uint32_t a = (line[x] & 0xff000000) >> 24; 175 line[x] = (r << rshift) | (g << gshift) | (b << bshift) | 176 ((a << ashift) & amask); 177 } 178 } 179 } 180 181 SDL_UnlockSurface( dst_surface ); 182 SDL_UnlockSurface( src_surface ); 183 184 SDL_UpdateRects( dst_surface, 1, &op.rd ); 185 } 186