Home | History | Annotate | Download | only in skin
      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
     79 
     80 #include "android/skin/argb.h"
     81 
     82 
     83 void
     84 skin_scaler_scale( SkinScaler*   scaler,
     85                    SDL_Surface*  dst_surface,
     86                    SDL_Surface*  src_surface,
     87                    int           sx,
     88                    int           sy,
     89                    int           sw,
     90                    int           sh )
     91 {
     92     ScaleOp   op;
     93 
     94     if ( !scaler->valid )
     95         return;
     96 
     97     SDL_LockSurface( src_surface );
     98     SDL_LockSurface( dst_surface );
     99     {
    100         op.scale     = scaler->scale;
    101         op.src_pitch = src_surface->pitch;
    102         op.src_line  = src_surface->pixels;
    103         op.src_w     = src_surface->w;
    104         op.src_h     = src_surface->h;
    105         op.dst_pitch = dst_surface->pitch;
    106         op.dst_line  = dst_surface->pixels;
    107 
    108         /* compute the destination rectangle */
    109         op.rd.x = (int)(sx * scaler->scale + scaler->xdisp);
    110         op.rd.y = (int)(sy * scaler->scale + scaler->ydisp);
    111         op.rd.w = (int)(ceil((sx + sw) * scaler->scale + scaler->xdisp)) - op.rd.x;
    112         op.rd.h = (int)(ceil((sy + sh) * scaler->scale + scaler->ydisp)) - op.rd.y;
    113 
    114         /* compute the starting source position in 16.16 format
    115          * and the corresponding increments */
    116         op.sx = (int)((op.rd.x - scaler->xdisp) * scaler->invscale * 65536);
    117         op.sy = (int)((op.rd.y - scaler->ydisp) * scaler->invscale * 65536);
    118 
    119         op.ix = (int)( scaler->invscale * 65536 );
    120         op.iy = op.ix;
    121 
    122         op.dst_line += op.rd.x*4 + op.rd.y*op.dst_pitch;
    123 
    124         if (op.scale >= 0.5 && op.scale <= 1.0)
    125             scale_05_to_10( &op );
    126         else if (op.scale > 1.0)
    127             scale_up_bilinear( &op );
    128         else
    129             scale_generic( &op );
    130     }
    131     SDL_UnlockSurface( dst_surface );
    132     SDL_UnlockSurface( src_surface );
    133 
    134     SDL_UpdateRects( dst_surface, 1, &op.rd );
    135 }
    136