src/render/software/SDL_render_sw.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 31 Mar 2013 12:48:50 -0400
changeset 7037 3fedf1f25b94
parent 6885 700f1b25f77f
child 7141 e276777b4247
permissions -rw-r--r--
Make SDL_SetError and friends unconditionally return -1.

This lets us change things like this...

if (Failed) {
SDL_SetError("We failed");
return -1;
}

...into this...

if (Failed) {
return SDL_SetError("We failed");
}


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