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 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