src/render/software/SDL_render_sw.c
author Jørgen P. Tjernø <jorgenpt@gmail.com>
Sat, 19 Apr 2014 13:15:41 -0700
changeset 8728 c7174f961388
parent 8149 681eb46b8ac4
child 8904 c38e754cafd3
permissions -rw-r--r--
Render: Allow empty cliprect.

This fixes an issue where an empty cliprect is treated the same as a NULL
cliprect, causing the render backends to disable clipping.

Also adds a new API, SDL_RenderIsClipEnabled(render) that allows you to
differentiate between:
- SDL_RenderSetClipRect(render, NULL)
- SDL_Rect r = {0,0,0,0}; SDL_RenderSetClipRect(render, &r);

Fixes https://bugzilla.libsdl.org/show_bug.cgi?id=2504
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if !SDL_RENDER_DISABLED
    24 
    25 #include "../SDL_sysrender.h"
    26 #include "SDL_render_sw_c.h"
    27 #include "SDL_hints.h"
    28 
    29 #include "SDL_draw.h"
    30 #include "SDL_blendfillrect.h"
    31 #include "SDL_blendline.h"
    32 #include "SDL_blendpoint.h"
    33 #include "SDL_drawline.h"
    34 #include "SDL_drawpoint.h"
    35 #include "SDL_rotate.h"
    36 
    37 /* SDL surface based renderer implementation */
    38 
    39 static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags);
    40 static void SW_WindowEvent(SDL_Renderer * renderer,
    41                            const SDL_WindowEvent *event);
    42 static int SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
    43 static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    44 static int SW_SetTextureColorMod(SDL_Renderer * renderer,
    45                                  SDL_Texture * texture);
    46 static int SW_SetTextureAlphaMod(SDL_Renderer * renderer,
    47                                  SDL_Texture * texture);
    48 static int SW_SetTextureBlendMode(SDL_Renderer * renderer,
    49                                   SDL_Texture * texture);
    50 static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    51                             const SDL_Rect * rect, const void *pixels,
    52                             int pitch);
    53 static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    54                           const SDL_Rect * rect, void **pixels, int *pitch);
    55 static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    56 static int SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
    57 static int SW_UpdateViewport(SDL_Renderer * renderer);
    58 static int SW_UpdateClipRect(SDL_Renderer * renderer);
    59 static int SW_RenderClear(SDL_Renderer * renderer);
    60 static int SW_RenderDrawPoints(SDL_Renderer * renderer,
    61                                const SDL_FPoint * points, int count);
    62 static int SW_RenderDrawLines(SDL_Renderer * renderer,
    63                               const SDL_FPoint * points, int count);
    64 static int SW_RenderFillRects(SDL_Renderer * renderer,
    65                               const SDL_FRect * rects, int count);
    66 static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    67                          const SDL_Rect * srcrect, const SDL_FRect * dstrect);
    68 static int SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
    69                           const SDL_Rect * srcrect, const SDL_FRect * dstrect,
    70                           const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
    71 static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    72                                Uint32 format, void * pixels, int pitch);
    73 static void SW_RenderPresent(SDL_Renderer * renderer);
    74 static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    75 static void SW_DestroyRenderer(SDL_Renderer * renderer);
    76 
    77 
    78 SDL_RenderDriver SW_RenderDriver = {
    79     SW_CreateRenderer,
    80     {
    81      "software",
    82      SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE,
    83      8,
    84      {
    85       SDL_PIXELFORMAT_RGB555,
    86       SDL_PIXELFORMAT_RGB565,
    87       SDL_PIXELFORMAT_RGB888,
    88       SDL_PIXELFORMAT_BGR888,
    89       SDL_PIXELFORMAT_ARGB8888,
    90       SDL_PIXELFORMAT_RGBA8888,
    91       SDL_PIXELFORMAT_ABGR8888,
    92       SDL_PIXELFORMAT_BGRA8888
    93      },
    94      0,
    95      0}
    96 };
    97 
    98 typedef struct
    99 {
   100     SDL_Surface *surface;
   101     SDL_Surface *window;
   102 } SW_RenderData;
   103 
   104 
   105 static SDL_Surface *
   106 SW_ActivateRenderer(SDL_Renderer * renderer)
   107 {
   108     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   109 
   110     if (!data->surface) {
   111         data->surface = data->window;
   112     }
   113     if (!data->surface) {
   114         SDL_Surface *surface = SDL_GetWindowSurface(renderer->window);
   115         if (surface) {
   116             data->surface = data->window = surface;
   117 
   118             SW_UpdateViewport(renderer);
   119             SW_UpdateClipRect(renderer);
   120         }
   121     }
   122     return data->surface;
   123 }
   124 
   125 SDL_Renderer *
   126 SW_CreateRendererForSurface(SDL_Surface * surface)
   127 {
   128     SDL_Renderer *renderer;
   129     SW_RenderData *data;
   130 
   131     if (!surface) {
   132         SDL_SetError("Can't create renderer for NULL surface");
   133         return NULL;
   134     }
   135 
   136     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   137     if (!renderer) {
   138         SDL_OutOfMemory();
   139         return NULL;
   140     }
   141 
   142     data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
   143     if (!data) {
   144         SW_DestroyRenderer(renderer);
   145         SDL_OutOfMemory();
   146         return NULL;
   147     }
   148     data->surface = surface;
   149 
   150     renderer->WindowEvent = SW_WindowEvent;
   151     renderer->GetOutputSize = SW_GetOutputSize;
   152     renderer->CreateTexture = SW_CreateTexture;
   153     renderer->SetTextureColorMod = SW_SetTextureColorMod;
   154     renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
   155     renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
   156     renderer->UpdateTexture = SW_UpdateTexture;
   157     renderer->LockTexture = SW_LockTexture;
   158     renderer->UnlockTexture = SW_UnlockTexture;
   159     renderer->SetRenderTarget = SW_SetRenderTarget;
   160     renderer->UpdateViewport = SW_UpdateViewport;
   161     renderer->UpdateClipRect = SW_UpdateClipRect;
   162     renderer->RenderClear = SW_RenderClear;
   163     renderer->RenderDrawPoints = SW_RenderDrawPoints;
   164     renderer->RenderDrawLines = SW_RenderDrawLines;
   165     renderer->RenderFillRects = SW_RenderFillRects;
   166     renderer->RenderCopy = SW_RenderCopy;
   167     renderer->RenderCopyEx = SW_RenderCopyEx;
   168     renderer->RenderReadPixels = SW_RenderReadPixels;
   169     renderer->RenderPresent = SW_RenderPresent;
   170     renderer->DestroyTexture = SW_DestroyTexture;
   171     renderer->DestroyRenderer = SW_DestroyRenderer;
   172     renderer->info = SW_RenderDriver.info;
   173     renderer->driverdata = data;
   174 
   175     SW_ActivateRenderer(renderer);
   176 
   177     return renderer;
   178 }
   179 
   180 SDL_Renderer *
   181 SW_CreateRenderer(SDL_Window * window, Uint32 flags)
   182 {
   183     SDL_Surface *surface;
   184 
   185     surface = SDL_GetWindowSurface(window);
   186     if (!surface) {
   187         return NULL;
   188     }
   189     return SW_CreateRendererForSurface(surface);
   190 }
   191 
   192 static void
   193 SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   194 {
   195     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   196 
   197     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   198         data->surface = NULL;
   199         data->window = NULL;
   200     }
   201 }
   202 
   203 static int
   204 SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
   205 {
   206     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   207 
   208     if (surface) {
   209         if (w) {
   210             *w = surface->w;
   211         }
   212         if (h) {
   213             *h = surface->h;
   214         }
   215         return 0;
   216     } else {
   217         SDL_SetError("Software renderer doesn't have an output surface");
   218         return -1;
   219     }
   220 }
   221 
   222 static int
   223 SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   224 {
   225     int bpp;
   226     Uint32 Rmask, Gmask, Bmask, Amask;
   227 
   228     if (!SDL_PixelFormatEnumToMasks
   229         (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   230         return SDL_SetError("Unknown texture format");
   231     }
   232 
   233     texture->driverdata =
   234         SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
   235                              Bmask, Amask);
   236     SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
   237                            texture->b);
   238     SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
   239     SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
   240 
   241     if (texture->access == SDL_TEXTUREACCESS_STATIC) {
   242         SDL_SetSurfaceRLE(texture->driverdata, 1);
   243     }
   244 
   245     if (!texture->driverdata) {
   246         return -1;
   247     }
   248     return 0;
   249 }
   250 
   251 static int
   252 SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   253 {
   254     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   255     return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
   256                                   texture->b);
   257 }
   258 
   259 static int
   260 SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   261 {
   262     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   263     return SDL_SetSurfaceAlphaMod(surface, texture->a);
   264 }
   265 
   266 static int
   267 SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   268 {
   269     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   270     return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
   271 }
   272 
   273 static int
   274 SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   275                  const SDL_Rect * rect, const void *pixels, int pitch)
   276 {
   277     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   278     Uint8 *src, *dst;
   279     int row;
   280     size_t length;
   281 
   282     if(SDL_MUSTLOCK(surface))
   283         SDL_LockSurface(surface);
   284     src = (Uint8 *) pixels;
   285     dst = (Uint8 *) surface->pixels +
   286                         rect->y * surface->pitch +
   287                         rect->x * surface->format->BytesPerPixel;
   288     length = rect->w * surface->format->BytesPerPixel;
   289     for (row = 0; row < rect->h; ++row) {
   290         SDL_memcpy(dst, src, length);
   291         src += pitch;
   292         dst += surface->pitch;
   293     }
   294     if(SDL_MUSTLOCK(surface))
   295         SDL_UnlockSurface(surface);
   296     return 0;
   297 }
   298 
   299 static int
   300 SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   301                const SDL_Rect * rect, void **pixels, int *pitch)
   302 {
   303     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   304 
   305     *pixels =
   306         (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
   307                   rect->x * surface->format->BytesPerPixel);
   308     *pitch = surface->pitch;
   309     return 0;
   310 }
   311 
   312 static void
   313 SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   314 {
   315 }
   316 
   317 static int
   318 SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   319 {
   320     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   321 
   322     if (texture ) {
   323         data->surface = (SDL_Surface *) texture->driverdata;
   324     } else {
   325         data->surface = data->window;
   326     }
   327     return 0;
   328 }
   329 
   330 static int
   331 SW_UpdateViewport(SDL_Renderer * renderer)
   332 {
   333     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   334     SDL_Surface *surface = data->surface;
   335 
   336     if (!surface) {
   337         /* We'll update the viewport after we recreate the surface */
   338         return 0;
   339     }
   340 
   341     SDL_SetClipRect(data->surface, &renderer->viewport);
   342     return 0;
   343 }
   344 
   345 static int
   346 SW_UpdateClipRect(SDL_Renderer * renderer)
   347 {
   348     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   349     SDL_Surface *surface = data->surface;
   350     if (surface) {
   351         if (renderer->clipping_enabled) {
   352             SDL_SetClipRect(surface, &renderer->clip_rect);
   353         } else {
   354             SDL_SetClipRect(surface, NULL);
   355         }
   356     }
   357     return 0;
   358 }
   359 
   360 static int
   361 SW_RenderClear(SDL_Renderer * renderer)
   362 {
   363     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   364     Uint32 color;
   365     SDL_Rect clip_rect;
   366 
   367     if (!surface) {
   368         return -1;
   369     }
   370 
   371     color = SDL_MapRGBA(surface->format,
   372                         renderer->r, renderer->g, renderer->b, renderer->a);
   373 
   374     /* By definition the clear ignores the clip rect */
   375     clip_rect = surface->clip_rect;
   376     SDL_SetClipRect(surface, NULL);
   377     SDL_FillRect(surface, NULL, color);
   378     SDL_SetClipRect(surface, &clip_rect);
   379     return 0;
   380 }
   381 
   382 static int
   383 SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
   384                     int count)
   385 {
   386     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   387     SDL_Point *final_points;
   388     int i, status;
   389 
   390     if (!surface) {
   391         return -1;
   392     }
   393 
   394     final_points = SDL_stack_alloc(SDL_Point, count);
   395     if (!final_points) {
   396         return SDL_OutOfMemory();
   397     }
   398     if (renderer->viewport.x || renderer->viewport.y) {
   399         int x = renderer->viewport.x;
   400         int y = renderer->viewport.y;
   401 
   402         for (i = 0; i < count; ++i) {
   403             final_points[i].x = (int)(x + points[i].x);
   404             final_points[i].y = (int)(y + points[i].y);
   405         }
   406     } else {
   407         for (i = 0; i < count; ++i) {
   408             final_points[i].x = (int)points[i].x;
   409             final_points[i].y = (int)points[i].y;
   410         }
   411     }
   412 
   413     /* Draw the points! */
   414     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   415         Uint32 color = SDL_MapRGBA(surface->format,
   416                                    renderer->r, renderer->g, renderer->b,
   417                                    renderer->a);
   418 
   419         status = SDL_DrawPoints(surface, final_points, count, color);
   420     } else {
   421         status = SDL_BlendPoints(surface, final_points, count,
   422                                 renderer->blendMode,
   423                                 renderer->r, renderer->g, renderer->b,
   424                                 renderer->a);
   425     }
   426     SDL_stack_free(final_points);
   427 
   428     return status;
   429 }
   430 
   431 static int
   432 SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
   433                    int count)
   434 {
   435     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   436     SDL_Point *final_points;
   437     int i, status;
   438 
   439     if (!surface) {
   440         return -1;
   441     }
   442 
   443     final_points = SDL_stack_alloc(SDL_Point, count);
   444     if (!final_points) {
   445         return SDL_OutOfMemory();
   446     }
   447     if (renderer->viewport.x || renderer->viewport.y) {
   448         int x = renderer->viewport.x;
   449         int y = renderer->viewport.y;
   450 
   451         for (i = 0; i < count; ++i) {
   452             final_points[i].x = (int)(x + points[i].x);
   453             final_points[i].y = (int)(y + points[i].y);
   454         }
   455     } else {
   456         for (i = 0; i < count; ++i) {
   457             final_points[i].x = (int)points[i].x;
   458             final_points[i].y = (int)points[i].y;
   459         }
   460     }
   461 
   462     /* Draw the lines! */
   463     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   464         Uint32 color = SDL_MapRGBA(surface->format,
   465                                    renderer->r, renderer->g, renderer->b,
   466                                    renderer->a);
   467 
   468         status = SDL_DrawLines(surface, final_points, count, color);
   469     } else {
   470         status = SDL_BlendLines(surface, final_points, count,
   471                                 renderer->blendMode,
   472                                 renderer->r, renderer->g, renderer->b,
   473                                 renderer->a);
   474     }
   475     SDL_stack_free(final_points);
   476 
   477     return status;
   478 }
   479 
   480 static int
   481 SW_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
   482 {
   483     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   484     SDL_Rect *final_rects;
   485     int i, status;
   486 
   487     if (!surface) {
   488         return -1;
   489     }
   490 
   491     final_rects = SDL_stack_alloc(SDL_Rect, count);
   492     if (!final_rects) {
   493         return SDL_OutOfMemory();
   494     }
   495     if (renderer->viewport.x || renderer->viewport.y) {
   496         int x = renderer->viewport.x;
   497         int y = renderer->viewport.y;
   498 
   499         for (i = 0; i < count; ++i) {
   500             final_rects[i].x = (int)(x + rects[i].x);
   501             final_rects[i].y = (int)(y + rects[i].y);
   502             final_rects[i].w = SDL_max((int)rects[i].w, 1);
   503             final_rects[i].h = SDL_max((int)rects[i].h, 1);
   504         }
   505     } else {
   506         for (i = 0; i < count; ++i) {
   507             final_rects[i].x = (int)rects[i].x;
   508             final_rects[i].y = (int)rects[i].y;
   509             final_rects[i].w = SDL_max((int)rects[i].w, 1);
   510             final_rects[i].h = SDL_max((int)rects[i].h, 1);
   511         }
   512     }
   513 
   514     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   515         Uint32 color = SDL_MapRGBA(surface->format,
   516                                    renderer->r, renderer->g, renderer->b,
   517                                    renderer->a);
   518         status = SDL_FillRects(surface, final_rects, count, color);
   519     } else {
   520         status = SDL_BlendFillRects(surface, final_rects, count,
   521                                     renderer->blendMode,
   522                                     renderer->r, renderer->g, renderer->b,
   523                                     renderer->a);
   524     }
   525     SDL_stack_free(final_rects);
   526 
   527     return status;
   528 }
   529 
   530 static int
   531 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   532               const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   533 {
   534     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   535     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   536     SDL_Rect final_rect;
   537 
   538     if (!surface) {
   539         return -1;
   540     }
   541 
   542     if (renderer->viewport.x || renderer->viewport.y) {
   543         final_rect.x = (int)(renderer->viewport.x + dstrect->x);
   544         final_rect.y = (int)(renderer->viewport.y + dstrect->y);
   545     } else {
   546         final_rect.x = (int)dstrect->x;
   547         final_rect.y = (int)dstrect->y;
   548     }
   549     final_rect.w = (int)dstrect->w;
   550     final_rect.h = (int)dstrect->h;
   551 
   552     if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {
   553         return SDL_BlitSurface(src, srcrect, surface, &final_rect);
   554     } else {
   555         return SDL_BlitScaled(src, srcrect, surface, &final_rect);
   556     }
   557 }
   558 
   559 static int
   560 GetScaleQuality(void)
   561 {
   562     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   563 
   564     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   565         return 0;
   566     } else {
   567         return 1;
   568     }
   569 }
   570 
   571 static int
   572 SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   573                 const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   574                 const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
   575 {
   576     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   577     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   578     SDL_Rect final_rect, tmp_rect;
   579     SDL_Surface *surface_rotated, *surface_scaled;
   580     Uint32 colorkey;
   581     int retval, dstwidth, dstheight, abscenterx, abscentery;
   582     double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
   583 
   584     if (!surface) {
   585         return -1;
   586     }
   587 
   588     if (renderer->viewport.x || renderer->viewport.y) {
   589         final_rect.x = (int)(renderer->viewport.x + dstrect->x);
   590         final_rect.y = (int)(renderer->viewport.y + dstrect->y);
   591     } else {
   592         final_rect.x = (int)dstrect->x;
   593         final_rect.y = (int)dstrect->y;
   594     }
   595     final_rect.w = (int)dstrect->w;
   596     final_rect.h = (int)dstrect->h;
   597 
   598     surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel,
   599                                           src->format->Rmask, src->format->Gmask,
   600                                           src->format->Bmask, src->format->Amask );
   601     if (surface_scaled) {
   602         SDL_GetColorKey(src, &colorkey);
   603         SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey);
   604         tmp_rect = final_rect;
   605         tmp_rect.x = 0;
   606         tmp_rect.y = 0;
   607 
   608         retval = SDL_BlitScaled(src, srcrect, surface_scaled, &tmp_rect);
   609         if (!retval) {
   610             SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, -angle, &dstwidth, &dstheight, &cangle, &sangle);
   611             surface_rotated = SDLgfx_rotateSurface(surface_scaled, -angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
   612             if(surface_rotated) {
   613                 /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
   614                 abscenterx = final_rect.x + (int)center->x;
   615                 abscentery = final_rect.y + (int)center->y;
   616                 /* Compensate the angle inversion to match the behaviour of the other backends */
   617                 sangle = -sangle;
   618 
   619                 /* Top Left */
   620                 px = final_rect.x - abscenterx;
   621                 py = final_rect.y - abscentery;
   622                 p1x = px * cangle - py * sangle + abscenterx;
   623                 p1y = px * sangle + py * cangle + abscentery;
   624 
   625                 /* Top Right */
   626                 px = final_rect.x + final_rect.w - abscenterx;
   627                 py = final_rect.y - abscentery;
   628                 p2x = px * cangle - py * sangle + abscenterx;
   629                 p2y = px * sangle + py * cangle + abscentery;
   630 
   631                 /* Bottom Left */
   632                 px = final_rect.x - abscenterx;
   633                 py = final_rect.y + final_rect.h - abscentery;
   634                 p3x = px * cangle - py * sangle + abscenterx;
   635                 p3y = px * sangle + py * cangle + abscentery;
   636 
   637                 /* Bottom Right */
   638                 px = final_rect.x + final_rect.w - abscenterx;
   639                 py = final_rect.y + final_rect.h - abscentery;
   640                 p4x = px * cangle - py * sangle + abscenterx;
   641                 p4y = px * sangle + py * cangle + abscentery;
   642 
   643                 tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
   644                 tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
   645                 tmp_rect.w = dstwidth;
   646                 tmp_rect.h = dstheight;
   647 
   648                 retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect);
   649                 SDL_FreeSurface(surface_scaled);
   650                 SDL_FreeSurface(surface_rotated);
   651                 return retval;
   652             }
   653         }
   654         return retval;
   655     }
   656 
   657     return -1;
   658 }
   659 
   660 static int
   661 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   662                     Uint32 format, void * pixels, int pitch)
   663 {
   664     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   665     Uint32 src_format;
   666     void *src_pixels;
   667     SDL_Rect final_rect;
   668 
   669     if (!surface) {
   670         return -1;
   671     }
   672 
   673     if (renderer->viewport.x || renderer->viewport.y) {
   674         final_rect.x = renderer->viewport.x + rect->x;
   675         final_rect.y = renderer->viewport.y + rect->y;
   676         final_rect.w = rect->w;
   677         final_rect.h = rect->h;
   678         rect = &final_rect;
   679     }
   680 
   681     if (rect->x < 0 || rect->x+rect->w > surface->w ||
   682         rect->y < 0 || rect->y+rect->h > surface->h) {
   683         return SDL_SetError("Tried to read outside of surface bounds");
   684     }
   685 
   686     src_format = surface->format->format;
   687     src_pixels = (void*)((Uint8 *) surface->pixels +
   688                     rect->y * surface->pitch +
   689                     rect->x * surface->format->BytesPerPixel);
   690 
   691     return SDL_ConvertPixels(rect->w, rect->h,
   692                              src_format, src_pixels, surface->pitch,
   693                              format, pixels, pitch);
   694 }
   695 
   696 static void
   697 SW_RenderPresent(SDL_Renderer * renderer)
   698 {
   699     SDL_Window *window = renderer->window;
   700 
   701     if (window) {
   702         SDL_UpdateWindowSurface(window);
   703     }
   704 }
   705 
   706 static void
   707 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   708 {
   709     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   710 
   711     SDL_FreeSurface(surface);
   712 }
   713 
   714 static void
   715 SW_DestroyRenderer(SDL_Renderer * renderer)
   716 {
   717     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   718 
   719     SDL_free(data);
   720     SDL_free(renderer);
   721 }
   722 
   723 #endif /* !SDL_RENDER_DISABLED */
   724 
   725 /* vi: set ts=4 sw=4 expandtab: */