src/render/software/SDL_render_sw.c
changeset 10612 6b2307dbec54
parent 10489 1e1ce9f6d215
child 10737 3406a0f8b041
equal deleted inserted replaced
10611:52ba31230c02 10612:6b2307dbec54
   237     SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
   237     SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
   238                            texture->b);
   238                            texture->b);
   239     SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
   239     SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
   240     SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
   240     SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
   241 
   241 
   242     if (texture->access == SDL_TEXTUREACCESS_STATIC) {
   242     /* Only RLE encode textures without an alpha channel since the RLE coder
       
   243      * discards the color values of pixels with an alpha value of zero.
       
   244      */
       
   245     if (texture->access == SDL_TEXTUREACCESS_STATIC && !Amask) {
   243         SDL_SetSurfaceRLE(texture->driverdata, 1);
   246         SDL_SetSurfaceRLE(texture->driverdata, 1);
   244     }
   247     }
   245 
   248 
   246     if (!texture->driverdata) {
   249     if (!texture->driverdata) {
   247         return -1;
   250         return -1;
   597                 const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
   600                 const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
   598 {
   601 {
   599     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   602     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   600     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   603     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   601     SDL_Rect final_rect, tmp_rect;
   604     SDL_Rect final_rect, tmp_rect;
   602     SDL_Surface *surface_rotated, *surface_scaled;
   605     SDL_Surface *src_clone, *src_rotated, *src_scaled;
   603     int retval, dstwidth, dstheight, abscenterx, abscentery;
   606     SDL_Surface *mask = NULL, *mask_rotated = NULL;
       
   607     int retval = 0, dstwidth, dstheight, abscenterx, abscentery;
   604     double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
   608     double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
       
   609     SDL_BlendMode blendmode;
       
   610     Uint8 alphaMod, rMod, gMod, bMod;
       
   611     int applyModulation = SDL_FALSE;
       
   612     int blitRequired = SDL_FALSE;
       
   613     int isOpaque = SDL_FALSE;
   605 
   614 
   606     if (!surface) {
   615     if (!surface) {
   607         return -1;
   616         return -1;
   608     }
   617     }
   609 
   618 
   615         final_rect.y = (int)dstrect->y;
   624         final_rect.y = (int)dstrect->y;
   616     }
   625     }
   617     final_rect.w = (int)dstrect->w;
   626     final_rect.w = (int)dstrect->w;
   618     final_rect.h = (int)dstrect->h;
   627     final_rect.h = (int)dstrect->h;
   619 
   628 
   620     /* SDLgfx_rotateSurface doesn't accept a source rectangle, so crop and scale if we need to */
       
   621     tmp_rect = final_rect;
   629     tmp_rect = final_rect;
   622     tmp_rect.x = 0;
   630     tmp_rect.x = 0;
   623     tmp_rect.y = 0;
   631     tmp_rect.y = 0;
   624     if (srcrect->w == final_rect.w && srcrect->h == final_rect.h && srcrect->x == 0 && srcrect->y == 0) {
   632 
   625         surface_scaled = src; /* but if we don't need to, just use the original */
   633     /* It is possible to encounter an RLE encoded surface here and locking it is
   626         retval = 0;
   634      * necessary because this code is going to access the pixel buffer directly.
   627     } else {
   635      */
   628         SDL_Surface *blit_src = src;
   636     if (SDL_MUSTLOCK(src)) {
   629         Uint32 colorkey;
   637         SDL_LockSurface(src);
   630         SDL_BlendMode blendMode;
   638     }
   631         Uint8 alphaMod, r, g, b;
   639 
   632         SDL_bool cloneSource = SDL_FALSE;
   640     /* Clone the source surface but use its pixel buffer directly.
   633 
   641      * The original source surface must be treated as read-only.
   634         surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel,
   642      */
   635                                               src->format->Rmask, src->format->Gmask,
   643     src_clone = SDL_CreateRGBSurfaceFrom(src->pixels, src->w, src->h, src->format->BitsPerPixel, src->pitch,
   636                                               src->format->Bmask, src->format->Amask );
   644                                          src->format->Rmask, src->format->Gmask,
   637         if (!surface_scaled) {
   645                                          src->format->Bmask, src->format->Amask);
   638             return -1;
   646     if (src_clone == NULL) {
   639         }
   647         if (SDL_MUSTLOCK(src)) {
   640 
   648             SDL_UnlockSurface(src);
   641         /* copy the color key, alpha mod, blend mode, and color mod so the scaled surface behaves like the source */
   649         }
   642         if (SDL_GetColorKey(src, &colorkey) == 0) {
   650         return -1;
   643             SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey);
   651     }
   644             cloneSource = SDL_TRUE;
   652 
   645         }
   653     SDL_GetSurfaceBlendMode(src, &blendmode);
   646         SDL_GetSurfaceAlphaMod(src, &alphaMod); /* these will be copied to surface_scaled below if necessary */
   654     SDL_GetSurfaceAlphaMod(src, &alphaMod);
   647         SDL_GetSurfaceBlendMode(src, &blendMode);
   655     SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod);
   648         SDL_GetSurfaceColorMod(src, &r, &g, &b);
   656 
   649 
   657     /* SDLgfx_rotateSurface only accepts 32-bit surfaces with a 8888 layout. Everything else has to be converted. */
   650         /* now we need to blit the src into surface_scaled. since we want to copy the colors from the source to
   658     if (src->format->BitsPerPixel != 32 || SDL_PIXELLAYOUT(src->format->format) != SDL_PACKEDLAYOUT_8888 || !src->format->Amask) {
   651          * surface_scaled rather than blend them, etc. we'll need to disable the blend mode, alpha mod, etc.
   659         blitRequired = SDL_TRUE;
   652          * but we don't want to modify src (in case it's being used on other threads), so we'll need to clone it
   660     }
   653          * before changing the blend options
   661 
   654          */
   662     /* If scaling and cropping is necessary, it has to be taken care of before the rotation. */
   655         cloneSource |= blendMode != SDL_BLENDMODE_NONE || (alphaMod & r & g & b) != 255;
   663     if (!(srcrect->w == final_rect.w && srcrect->h == final_rect.h && srcrect->x == 0 && srcrect->y == 0)) {
   656         if (cloneSource) {
   664         blitRequired = SDL_TRUE;
   657             blit_src = SDL_ConvertSurface(src, src->format, src->flags); /* clone src */
   665     }
   658             if (!blit_src) {
   666 
   659                 SDL_FreeSurface(surface_scaled);
   667     /* The color and alpha modulation has to be applied before the rotation when using the NONE and MOD blend modes. */
   660                 return -1;
   668     if ((blendmode == SDL_BLENDMODE_NONE || blendmode == SDL_BLENDMODE_MOD) && (alphaMod & rMod & gMod & bMod) != 255) {
   661             }
   669         applyModulation = SDL_TRUE;
   662             SDL_SetSurfaceAlphaMod(blit_src, 255); /* disable all blending options in blit_src */
   670         SDL_SetSurfaceAlphaMod(src_clone, alphaMod);
   663             SDL_SetSurfaceBlendMode(blit_src, SDL_BLENDMODE_NONE);
   671         SDL_SetSurfaceColorMod(src_clone, rMod, gMod, bMod);
   664             SDL_SetColorKey(blit_src, 0, 0);
   672     }
   665             SDL_SetSurfaceColorMod(blit_src, 255, 255, 255);
   673 
   666             SDL_SetSurfaceRLE(blit_src, 0); /* don't RLE encode a surface we'll only use once */
   674     /* Opaque surfaces are much easier to handle with the NONE blend mode. */
   667 
   675     if (blendmode == SDL_BLENDMODE_NONE && !src->format->Amask && alphaMod == 255) {
   668             SDL_SetSurfaceAlphaMod(surface_scaled, alphaMod); /* copy blending options to surface_scaled */
   676         isOpaque = SDL_TRUE;
   669             SDL_SetSurfaceBlendMode(surface_scaled, blendMode);
   677     }
   670             SDL_SetSurfaceColorMod(surface_scaled, r, g, b);
   678 
   671         }
   679     /* The NONE blend mode requires a mask for non-opaque surfaces. This mask will be used
   672 
   680      * to clear the pixels in the destination surface. The other steps are explained below.
   673         retval = SDL_BlitScaled(blit_src, srcrect, surface_scaled, &tmp_rect);
   681      */
   674         if (blit_src != src) {
   682     if (blendmode == SDL_BLENDMODE_NONE && !isOpaque) {
   675             SDL_FreeSurface(blit_src);
   683         mask = SDL_CreateRGBSurface(0, final_rect.w, final_rect.h, 32,
   676         }
   684                                     0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
   677     }
   685         if (mask == NULL) {
       
   686             retval = -1;
       
   687         } else {
       
   688             SDL_SetSurfaceBlendMode(mask, SDL_BLENDMODE_MOD);
       
   689         }
       
   690     }
       
   691 
       
   692     /* Create a new surface should there be a format mismatch or if scaling, cropping,
       
   693      * or modulation is required. It's possible to use the source surface directly otherwise.
       
   694      */
       
   695     if (!retval && (blitRequired || applyModulation)) {
       
   696         SDL_Rect scale_rect = tmp_rect;
       
   697         src_scaled = SDL_CreateRGBSurface(0, final_rect.w, final_rect.h, 32,
       
   698                                           0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
       
   699         if (src_scaled == NULL) {
       
   700             retval = -1;
       
   701         } else {
       
   702             SDL_SetSurfaceBlendMode(src_clone, SDL_BLENDMODE_NONE);
       
   703             retval = SDL_BlitScaled(src_clone, srcrect, src_scaled, &scale_rect);
       
   704             SDL_FreeSurface(src_clone);
       
   705             src_clone = src_scaled;
       
   706             src_scaled = NULL;
       
   707         }
       
   708     }
       
   709 
       
   710     /* SDLgfx_rotateSurface is going to make decisions depending on the blend mode. */
       
   711     SDL_SetSurfaceBlendMode(src_clone, blendmode);
   678 
   712 
   679     if (!retval) {
   713     if (!retval) {
   680         SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, &dstwidth, &dstheight, &cangle, &sangle);
   714         SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, &dstwidth, &dstheight, &cangle, &sangle);
   681         surface_rotated = SDLgfx_rotateSurface(surface_scaled, angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
   715         src_rotated = SDLgfx_rotateSurface(src_clone, angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
   682         if(surface_rotated) {
   716         if (src_rotated == NULL) {
       
   717             retval = -1;
       
   718         }
       
   719         if (!retval && mask != NULL) {
       
   720             /* The mask needed for the NONE blend mode gets rotated with the same parameters. */
       
   721             mask_rotated = SDLgfx_rotateSurface(mask, angle, dstwidth/2, dstheight/2, SDL_FALSE, 0, 0, dstwidth, dstheight, cangle, sangle);
       
   722             if (mask_rotated == NULL) {
       
   723                 retval = -1;
       
   724             }
       
   725         }
       
   726         if (!retval) {
   683             /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
   727             /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
   684             abscenterx = final_rect.x + (int)center->x;
   728             abscenterx = final_rect.x + (int)center->x;
   685             abscentery = final_rect.y + (int)center->y;
   729             abscentery = final_rect.y + (int)center->y;
   686             /* Compensate the angle inversion to match the behaviour of the other backends */
   730             /* Compensate the angle inversion to match the behaviour of the other backends */
   687             sangle = -sangle;
   731             sangle = -sangle;
   713             tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
   757             tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
   714             tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
   758             tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
   715             tmp_rect.w = dstwidth;
   759             tmp_rect.w = dstwidth;
   716             tmp_rect.h = dstheight;
   760             tmp_rect.h = dstheight;
   717 
   761 
   718             retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect);
   762             /* The NONE blend mode needs some special care with non-opaque surfaces.
   719             SDL_FreeSurface(surface_rotated);
   763              * Other blend modes or opaque surfaces can be blitted directly.
   720         }
   764              */
   721     }
   765             if (blendmode != SDL_BLENDMODE_NONE || isOpaque) {
   722 
   766                 if (applyModulation == SDL_FALSE) {
   723     if (surface_scaled != src) {
   767                     /* If the modulation wasn't already applied, make it happen now. */
   724         SDL_FreeSurface(surface_scaled);
   768                     SDL_SetSurfaceAlphaMod(src_rotated, alphaMod);
       
   769                     SDL_SetSurfaceColorMod(src_rotated, rMod, gMod, bMod);
       
   770                 }
       
   771                 retval = SDL_BlitSurface(src_rotated, NULL, surface, &tmp_rect);
       
   772             } else {
       
   773                 /* The NONE blend mode requires three steps to get the pixels onto the destination surface.
       
   774                  * First, the area where the rotated pixels will be blitted to get set to zero.
       
   775                  * This is accomplished by simply blitting a mask with the NONE blend mode.
       
   776                  * The colorkey set by the rotate function will discard the correct pixels.
       
   777                  */
       
   778                 SDL_Rect mask_rect = tmp_rect;
       
   779                 SDL_SetSurfaceBlendMode(mask_rotated, SDL_BLENDMODE_NONE);
       
   780                 retval = SDL_BlitSurface(mask_rotated, NULL, surface, &mask_rect);
       
   781                 if (!retval) {
       
   782                     /* The next step copies the alpha value. This is done with the BLEND blend mode and
       
   783                      * by modulating the source colors with 0. Since the destination is all zeros, this
       
   784                      * will effectively set the destination alpha to the source alpha.
       
   785                      */
       
   786                     SDL_SetSurfaceColorMod(src_rotated, 0, 0, 0);
       
   787                     mask_rect = tmp_rect;
       
   788                     retval = SDL_BlitSurface(src_rotated, NULL, surface, &mask_rect);
       
   789                     if (!retval) {
       
   790                         /* The last step gets the color values in place. The ADD blend mode simply adds them to
       
   791                          * the destination (where the color values are all zero). However, because the ADD blend
       
   792                          * mode modulates the colors with the alpha channel, a surface without an alpha mask needs
       
   793                          * to be created. This makes all source pixels opaque and the colors get copied correctly.
       
   794                          */
       
   795                         SDL_Surface *src_rotated_rgb;
       
   796                         src_rotated_rgb = SDL_CreateRGBSurfaceFrom(src_rotated->pixels, src_rotated->w, src_rotated->h,
       
   797                                                                    src_rotated->format->BitsPerPixel, src_rotated->pitch,
       
   798                                                                    src_rotated->format->Rmask, src_rotated->format->Gmask,
       
   799                                                                    src_rotated->format->Bmask, 0);
       
   800                         if (src_rotated_rgb == NULL) {
       
   801                             retval = -1;
       
   802                         } else {
       
   803                             SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD);
       
   804                             retval = SDL_BlitSurface(src_rotated_rgb, NULL, surface, &tmp_rect);
       
   805                             SDL_FreeSurface(src_rotated_rgb);
       
   806                         }
       
   807                     }
       
   808                 }
       
   809                 SDL_FreeSurface(mask_rotated);
       
   810             }
       
   811             if (src_rotated != NULL) {
       
   812                 SDL_FreeSurface(src_rotated);
       
   813             }
       
   814         }
       
   815     }
       
   816 
       
   817     if (SDL_MUSTLOCK(src)) {
       
   818         SDL_UnlockSurface(src);
       
   819     }
       
   820     if (mask != NULL) {
       
   821         SDL_FreeSurface(mask);
       
   822     }
       
   823     if (src_clone != NULL) {
       
   824         SDL_FreeSurface(src_clone);
   725     }
   825     }
   726     return retval;
   826     return retval;
   727 }
   827 }
   728 
   828 
   729 static int
   829 static int