/* Copyright (C) 2008 The Android Open Source Project ** ** This software is licensed under the terms of the GNU General Public ** License version 2, as published by the Free Software Foundation, and ** may be copied, distributed, and modified under those terms. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. */ #include "android/skin/scaler.h" #include #include struct SkinScaler { double scale; double xdisp, ydisp; double invscale; int valid; }; static SkinScaler _scaler0; SkinScaler* skin_scaler_create( void ) { _scaler0.scale = 1.0; _scaler0.xdisp = 0.0; _scaler0.ydisp = 0.0; _scaler0.invscale = 1.0; return &_scaler0; } /* change the scale of a given scaler. returns 0 on success, or -1 in case of * problem (unsupported scale) */ int skin_scaler_set( SkinScaler* scaler, double scale, double xdisp, double ydisp ) { /* right now, we only support scales in the 0.5 .. 1.0 range */ if (scale < 0.1) scale = 0.1; else if (scale > 6.0) scale = 6.0; scaler->scale = scale; scaler->xdisp = xdisp; scaler->ydisp = ydisp; scaler->invscale = 1/scale; scaler->valid = 1; return 0; } void skin_scaler_free( SkinScaler* scaler ) { scaler=scaler; } typedef struct { SDL_Rect rd; /* destination rectangle */ int sx, sy; /* source start position in 16.16 format */ int ix, iy; /* source increments in 16.16 format */ int src_pitch; int src_w; int src_h; int dst_pitch; uint8_t* dst_line; uint8_t* src_line; double scale; } ScaleOp; #define ARGB_SCALE_GENERIC scale_generic #define ARGB_SCALE_05_TO_10 scale_05_to_10 #define ARGB_SCALE_UP_BILINEAR scale_up_bilinear /* #define ARGB_SCALE_UP_QUICK_4x4 scale_up_quick_4x4 UNUSED */ #include "android/skin/argb.h" void skin_scaler_get_scaled_rect( SkinScaler* scaler, SkinRect* srect, SkinRect* drect ) { int sx = srect->pos.x; int sy = srect->pos.y; int sw = srect->size.w; int sh = srect->size.h; double scale = scaler->scale; if (!scaler->valid) { drect[0] = srect[0]; return; } drect->pos.x = (int)(sx * scale + scaler->xdisp); drect->pos.y = (int)(sy * scale + scaler->ydisp); drect->size.w = (int)(ceil((sx + sw) * scale + scaler->xdisp)) - drect->pos.x; drect->size.h = (int)(ceil((sy + sh) * scale + scaler->ydisp)) - drect->pos.y; } void skin_scaler_scale( SkinScaler* scaler, SDL_Surface* dst_surface, SDL_Surface* src_surface, int sx, int sy, int sw, int sh ) { ScaleOp op; if ( !scaler->valid ) return; SDL_LockSurface( src_surface ); SDL_LockSurface( dst_surface ); { op.scale = scaler->scale; op.src_pitch = src_surface->pitch; op.src_line = src_surface->pixels; op.src_w = src_surface->w; op.src_h = src_surface->h; op.dst_pitch = dst_surface->pitch; op.dst_line = dst_surface->pixels; /* compute the destination rectangle */ op.rd.x = (int)(sx * scaler->scale + scaler->xdisp); op.rd.y = (int)(sy * scaler->scale + scaler->ydisp); op.rd.w = (int)(ceil((sx + sw) * scaler->scale + scaler->xdisp)) - op.rd.x; op.rd.h = (int)(ceil((sy + sh) * scaler->scale + scaler->ydisp)) - op.rd.y; /* compute the starting source position in 16.16 format * and the corresponding increments */ op.sx = (int)((op.rd.x - scaler->xdisp) * scaler->invscale * 65536); op.sy = (int)((op.rd.y - scaler->ydisp) * scaler->invscale * 65536); op.ix = (int)( scaler->invscale * 65536 ); op.iy = op.ix; op.dst_line += op.rd.x*4 + op.rd.y*op.dst_pitch; if (op.scale >= 0.5 && op.scale <= 1.0) scale_05_to_10( &op ); else if (op.scale > 1.0) scale_up_bilinear( &op ); else scale_generic( &op ); } SDL_UnlockSurface( dst_surface ); SDL_UnlockSurface( src_surface ); SDL_UpdateRects( dst_surface, 1, &op.rd ); }