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