src/render/software/SDL_render_sw.c
changeset 9762 5c4a85c5b648
parent 9760 2f5a57f86e24
child 9998 f67cf37e9cd4
     1.1 --- a/src/render/software/SDL_render_sw.c	Fri Jun 19 23:12:13 2015 -0700
     1.2 +++ b/src/render/software/SDL_render_sw.c	Fri Jun 19 23:20:43 2015 -0700
     1.3 @@ -600,7 +600,6 @@
     1.4      SDL_Surface *src = (SDL_Surface *) texture->driverdata;
     1.5      SDL_Rect final_rect, tmp_rect;
     1.6      SDL_Surface *surface_rotated, *surface_scaled;
     1.7 -    Uint32 colorkey;
     1.8      int retval, dstwidth, dstheight, abscenterx, abscentery;
     1.9      double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
    1.10  
    1.11 @@ -618,66 +617,113 @@
    1.12      final_rect.w = (int)dstrect->w;
    1.13      final_rect.h = (int)dstrect->h;
    1.14  
    1.15 -    surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel,
    1.16 -                                          src->format->Rmask, src->format->Gmask,
    1.17 -                                          src->format->Bmask, src->format->Amask );
    1.18 -    if (surface_scaled) {
    1.19 -        SDL_GetColorKey(src, &colorkey);
    1.20 -        SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey);
    1.21 -        tmp_rect = final_rect;
    1.22 -        tmp_rect.x = 0;
    1.23 -        tmp_rect.y = 0;
    1.24 +    /* SDLgfx_rotateSurface doesn't accept a source rectangle, so crop and scale if we need to */
    1.25 +    tmp_rect = final_rect;
    1.26 +    tmp_rect.x = 0;
    1.27 +    tmp_rect.y = 0;
    1.28 +    if (srcrect->w == final_rect.w && srcrect->h == final_rect.h && srcrect->x == 0 && srcrect->y == 0) {
    1.29 +        surface_scaled = src; /* but if we don't need to, just use the original */
    1.30 +        retval = 0;
    1.31 +    } else {
    1.32 +        SDL_Surface *blit_src = src;
    1.33 +        Uint32 colorkey;
    1.34 +        SDL_BlendMode blendMode;
    1.35 +        Uint8 alphaMod, r, g, b;
    1.36 +        SDL_bool cloneSource = SDL_FALSE;
    1.37  
    1.38 -        retval = SDL_BlitScaled(src, srcrect, surface_scaled, &tmp_rect);
    1.39 -        if (!retval) {
    1.40 -            SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, -angle, &dstwidth, &dstheight, &cangle, &sangle);
    1.41 -            surface_rotated = SDLgfx_rotateSurface(surface_scaled, -angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
    1.42 -            if(surface_rotated) {
    1.43 -                /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
    1.44 -                abscenterx = final_rect.x + (int)center->x;
    1.45 -                abscentery = final_rect.y + (int)center->y;
    1.46 -                /* Compensate the angle inversion to match the behaviour of the other backends */
    1.47 -                sangle = -sangle;
    1.48 +        surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel,
    1.49 +                                              src->format->Rmask, src->format->Gmask,
    1.50 +                                              src->format->Bmask, src->format->Amask );
    1.51 +        if (!surface_scaled) {
    1.52 +            return -1;
    1.53 +        }
    1.54  
    1.55 -                /* Top Left */
    1.56 -                px = final_rect.x - abscenterx;
    1.57 -                py = final_rect.y - abscentery;
    1.58 -                p1x = px * cangle - py * sangle + abscenterx;
    1.59 -                p1y = px * sangle + py * cangle + abscentery;
    1.60 +        /* copy the color key, alpha mod, blend mode, and color mod so the scaled surface behaves like the source */
    1.61 +        if (SDL_GetColorKey(src, &colorkey) == 0) {
    1.62 +            SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey);
    1.63 +            cloneSource = SDL_TRUE;
    1.64 +        }
    1.65 +        SDL_GetSurfaceAlphaMod(src, &alphaMod); /* these will be copied to surface_scaled below if necessary */
    1.66 +        SDL_GetSurfaceBlendMode(src, &blendMode);
    1.67 +        SDL_GetSurfaceColorMod(src, &r, &g, &b);
    1.68  
    1.69 -                /* Top Right */
    1.70 -                px = final_rect.x + final_rect.w - abscenterx;
    1.71 -                py = final_rect.y - abscentery;
    1.72 -                p2x = px * cangle - py * sangle + abscenterx;
    1.73 -                p2y = px * sangle + py * cangle + abscentery;
    1.74 +        /* now we need to blit the src into surface_scaled. since we want to copy the colors from the source to
    1.75 +         * surface_scaled rather than blend them, etc. we'll need to disable the blend mode, alpha mod, etc.
    1.76 +         * but we don't want to modify src (in case it's being used on other threads), so we'll need to clone it
    1.77 +         * before changing the blend options
    1.78 +         */
    1.79 +        cloneSource |= blendMode != SDL_BLENDMODE_NONE || (alphaMod & r & g & b) != 255;
    1.80 +        if (cloneSource) {
    1.81 +            blit_src = SDL_ConvertSurface(src, src->format, src->flags); /* clone src */
    1.82 +            if (!blit_src) {
    1.83 +                SDL_FreeSurface(surface_scaled);
    1.84 +                return -1;
    1.85 +            }
    1.86 +            SDL_SetSurfaceAlphaMod(blit_src, 255); /* disable all blending options in blit_src */
    1.87 +            SDL_SetSurfaceBlendMode(blit_src, SDL_BLENDMODE_NONE);
    1.88 +            SDL_SetColorKey(blit_src, 0, 0);
    1.89 +            SDL_SetSurfaceColorMod(blit_src, 255, 255, 255);
    1.90 +            SDL_SetSurfaceRLE(blit_src, 0); /* don't RLE encode a surface we'll only use once */
    1.91  
    1.92 -                /* Bottom Left */
    1.93 -                px = final_rect.x - abscenterx;
    1.94 -                py = final_rect.y + final_rect.h - abscentery;
    1.95 -                p3x = px * cangle - py * sangle + abscenterx;
    1.96 -                p3y = px * sangle + py * cangle + abscentery;
    1.97 +            SDL_SetSurfaceAlphaMod(surface_scaled, alphaMod); /* copy blending options to surface_scaled */
    1.98 +            SDL_SetSurfaceBlendMode(surface_scaled, blendMode);
    1.99 +            SDL_SetSurfaceColorMod(surface_scaled, r, g, b);
   1.100 +        }
   1.101  
   1.102 -                /* Bottom Right */
   1.103 -                px = final_rect.x + final_rect.w - abscenterx;
   1.104 -                py = final_rect.y + final_rect.h - abscentery;
   1.105 -                p4x = px * cangle - py * sangle + abscenterx;
   1.106 -                p4y = px * sangle + py * cangle + abscentery;
   1.107 -
   1.108 -                tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
   1.109 -                tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
   1.110 -                tmp_rect.w = dstwidth;
   1.111 -                tmp_rect.h = dstheight;
   1.112 -
   1.113 -                retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect);
   1.114 -                SDL_FreeSurface(surface_scaled);
   1.115 -                SDL_FreeSurface(surface_rotated);
   1.116 -                return retval;
   1.117 -            }
   1.118 +        retval = SDL_BlitScaled(blit_src, srcrect, surface_scaled, &tmp_rect);
   1.119 +        if (blit_src != src) {
   1.120 +            SDL_FreeSurface(blit_src);
   1.121          }
   1.122 -        return retval;
   1.123      }
   1.124  
   1.125 -    return -1;
   1.126 +    if (!retval) {
   1.127 +        SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, -angle, &dstwidth, &dstheight, &cangle, &sangle);
   1.128 +        surface_rotated = SDLgfx_rotateSurface(surface_scaled, -angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
   1.129 +        if(surface_rotated) {
   1.130 +            /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
   1.131 +            abscenterx = final_rect.x + (int)center->x;
   1.132 +            abscentery = final_rect.y + (int)center->y;
   1.133 +            /* Compensate the angle inversion to match the behaviour of the other backends */
   1.134 +            sangle = -sangle;
   1.135 +
   1.136 +            /* Top Left */
   1.137 +            px = final_rect.x - abscenterx;
   1.138 +            py = final_rect.y - abscentery;
   1.139 +            p1x = px * cangle - py * sangle + abscenterx;
   1.140 +            p1y = px * sangle + py * cangle + abscentery;
   1.141 +
   1.142 +            /* Top Right */
   1.143 +            px = final_rect.x + final_rect.w - abscenterx;
   1.144 +            py = final_rect.y - abscentery;
   1.145 +            p2x = px * cangle - py * sangle + abscenterx;
   1.146 +            p2y = px * sangle + py * cangle + abscentery;
   1.147 +
   1.148 +            /* Bottom Left */
   1.149 +            px = final_rect.x - abscenterx;
   1.150 +            py = final_rect.y + final_rect.h - abscentery;
   1.151 +            p3x = px * cangle - py * sangle + abscenterx;
   1.152 +            p3y = px * sangle + py * cangle + abscentery;
   1.153 +
   1.154 +            /* Bottom Right */
   1.155 +            px = final_rect.x + final_rect.w - abscenterx;
   1.156 +            py = final_rect.y + final_rect.h - abscentery;
   1.157 +            p4x = px * cangle - py * sangle + abscenterx;
   1.158 +            p4y = px * sangle + py * cangle + abscentery;
   1.159 +
   1.160 +            tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
   1.161 +            tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
   1.162 +            tmp_rect.w = dstwidth;
   1.163 +            tmp_rect.h = dstheight;
   1.164 +
   1.165 +            retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect);
   1.166 +            SDL_FreeSurface(surface_rotated);
   1.167 +        }
   1.168 +    }
   1.169 +
   1.170 +    if (surface_scaled != src) {
   1.171 +        SDL_FreeSurface(surface_scaled);
   1.172 +    }
   1.173 +    return retval;
   1.174  }
   1.175  
   1.176  static int