src/video/SDL_renderer_sw.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 16 Nov 2009 07:13:07 +0000
changeset 3435 9f62f47d989b
parent 3427 36cf454ba065
child 3536 0267b8b1595c
permissions -rw-r--r--
You can specify the format for pixel data in SDL_RenderReadPixels() and SDL_RenderWritePixels()
This code still doesn't quite work yet. :)
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_video.h"
    25 #include "SDL_sysvideo.h"
    26 #include "SDL_pixels_c.h"
    27 #include "SDL_rect_c.h"
    28 #include "SDL_yuv_sw_c.h"
    29 
    30 
    31 /* SDL surface based renderer implementation */
    32 
    33 static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags);
    34 static int SW_ActivateRenderer(SDL_Renderer * renderer);
    35 static int SW_DisplayModeChanged(SDL_Renderer * renderer);
    36 static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    37 static int SW_QueryTexturePixels(SDL_Renderer * renderer,
    38                                  SDL_Texture * texture, void **pixels,
    39                                  int *pitch);
    40 static int SW_SetTexturePalette(SDL_Renderer * renderer,
    41                                 SDL_Texture * texture,
    42                                 const SDL_Color * colors, int firstcolor,
    43                                 int ncolors);
    44 static int SW_GetTexturePalette(SDL_Renderer * renderer,
    45                                 SDL_Texture * texture, SDL_Color * colors,
    46                                 int firstcolor, int ncolors);
    47 static int SW_SetTextureColorMod(SDL_Renderer * renderer,
    48                                  SDL_Texture * texture);
    49 static int SW_SetTextureAlphaMod(SDL_Renderer * renderer,
    50                                  SDL_Texture * texture);
    51 static int SW_SetTextureBlendMode(SDL_Renderer * renderer,
    52                                   SDL_Texture * texture);
    53 static int SW_SetTextureScaleMode(SDL_Renderer * renderer,
    54                                   SDL_Texture * texture);
    55 static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    56                             const SDL_Rect * rect, const void *pixels,
    57                             int pitch);
    58 static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    59                           const SDL_Rect * rect, int markDirty, void **pixels,
    60                           int *pitch);
    61 static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    62 static int SW_RenderPoint(SDL_Renderer * renderer, int x, int y);
    63 static int SW_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2,
    64                          int y2);
    65 static int SW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect);
    66 static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    67                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    68 static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    69                                Uint32 format, void * pixels, int pitch);
    70 static int SW_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    71                                 Uint32 format, const 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_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
    82       SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
    83       SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_PRESENTVSYNC),
    84      (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
    85       SDL_TEXTUREMODULATE_ALPHA),
    86      (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK |
    87       SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD),
    88      (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST),
    89      14,
    90      {
    91       SDL_PIXELFORMAT_INDEX8,
    92       SDL_PIXELFORMAT_RGB555,
    93       SDL_PIXELFORMAT_RGB565,
    94       SDL_PIXELFORMAT_RGB888,
    95       SDL_PIXELFORMAT_BGR888,
    96       SDL_PIXELFORMAT_ARGB8888,
    97       SDL_PIXELFORMAT_RGBA8888,
    98       SDL_PIXELFORMAT_ABGR8888,
    99       SDL_PIXELFORMAT_BGRA8888,
   100       SDL_PIXELFORMAT_YV12,
   101       SDL_PIXELFORMAT_IYUV,
   102       SDL_PIXELFORMAT_YUY2,
   103       SDL_PIXELFORMAT_UYVY,
   104       SDL_PIXELFORMAT_YVYU},
   105      0,
   106      0}
   107 };
   108 
   109 typedef struct
   110 {
   111     Uint32 format;
   112     SDL_bool updateSize;
   113     int current_texture;
   114     SDL_Texture *texture[3];
   115     SDL_Surface surface;
   116     SDL_Renderer *renderer;
   117     SDL_DirtyRectList dirty;
   118 } SW_RenderData;
   119 
   120 static SDL_Texture *
   121 CreateTexture(SDL_Renderer * renderer, Uint32 format, int w, int h)
   122 {
   123     SDL_Texture *texture;
   124 
   125     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
   126     if (!texture) {
   127         SDL_OutOfMemory();
   128         return NULL;
   129     }
   130 
   131     texture->format = format;
   132     texture->access = SDL_TEXTUREACCESS_STREAMING;
   133     texture->w = w;
   134     texture->h = h;
   135     texture->renderer = renderer;
   136 
   137     if (renderer->CreateTexture(renderer, texture) < 0) {
   138         SDL_free(texture);
   139         return NULL;
   140     }
   141     return texture;
   142 }
   143 
   144 static void
   145 DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   146 {
   147     renderer->DestroyTexture(renderer, texture);
   148     SDL_free(texture);
   149 }
   150 
   151 static int
   152 DisplayPaletteChanged(void *userdata, SDL_Palette * palette)
   153 {
   154     SW_RenderData *data = (SW_RenderData *) userdata;
   155     int i;
   156 
   157     for (i = 0; i < SDL_arraysize(data->texture); ++i) {
   158         if (data->texture[i] && data->renderer->SetTexturePalette) {
   159             data->renderer->SetTexturePalette(data->renderer,
   160                                               data->texture[i],
   161                                               palette->colors, 0,
   162                                               palette->ncolors);
   163         }
   164     }
   165     return 0;
   166 }
   167 
   168 void
   169 Setup_SoftwareRenderer(SDL_Renderer * renderer)
   170 {
   171     renderer->CreateTexture = SW_CreateTexture;
   172     renderer->QueryTexturePixels = SW_QueryTexturePixels;
   173     renderer->SetTexturePalette = SW_SetTexturePalette;
   174     renderer->GetTexturePalette = SW_GetTexturePalette;
   175     renderer->SetTextureColorMod = SW_SetTextureColorMod;
   176     renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
   177     renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
   178     renderer->SetTextureScaleMode = SW_SetTextureScaleMode;
   179     renderer->UpdateTexture = SW_UpdateTexture;
   180     renderer->LockTexture = SW_LockTexture;
   181     renderer->UnlockTexture = SW_UnlockTexture;
   182     renderer->DestroyTexture = SW_DestroyTexture;
   183 
   184     renderer->info.mod_modes = SW_RenderDriver.info.mod_modes;
   185     renderer->info.blend_modes = SW_RenderDriver.info.blend_modes;
   186     renderer->info.scale_modes = SW_RenderDriver.info.scale_modes;
   187     renderer->info.num_texture_formats =
   188         SW_RenderDriver.info.num_texture_formats;
   189     SDL_memcpy(renderer->info.texture_formats,
   190                SW_RenderDriver.info.texture_formats,
   191                sizeof(renderer->info.texture_formats));;
   192     renderer->info.max_texture_width = SW_RenderDriver.info.max_texture_width;
   193     renderer->info.max_texture_height =
   194         SW_RenderDriver.info.max_texture_height;
   195 }
   196 
   197 SDL_Renderer *
   198 SW_CreateRenderer(SDL_Window * window, Uint32 flags)
   199 {
   200     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   201     SDL_DisplayMode *displayMode = &display->current_mode;
   202     SDL_Renderer *renderer;
   203     SW_RenderData *data;
   204     int i, n;
   205     int bpp;
   206     Uint32 Rmask, Gmask, Bmask, Amask;
   207     Uint32 renderer_flags;
   208     const char *desired_driver;
   209 
   210     if (!SDL_PixelFormatEnumToMasks
   211         (displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   212         SDL_SetError("Unknown display format");
   213         return NULL;
   214     }
   215 
   216     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   217     if (!renderer) {
   218         SDL_OutOfMemory();
   219         return NULL;
   220     }
   221 
   222     data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
   223     if (!data) {
   224         SW_DestroyRenderer(renderer);
   225         SDL_OutOfMemory();
   226         return NULL;
   227     }
   228     renderer->ActivateRenderer = SW_ActivateRenderer;
   229     renderer->DisplayModeChanged = SW_DisplayModeChanged;
   230 
   231     renderer->RenderPoint = SW_RenderPoint;
   232     renderer->RenderLine = SW_RenderLine;
   233     renderer->RenderFill = SW_RenderFill;
   234     renderer->RenderCopy = SW_RenderCopy;
   235     renderer->RenderReadPixels = SW_RenderReadPixels;
   236     renderer->RenderWritePixels = SW_RenderWritePixels;
   237     renderer->RenderPresent = SW_RenderPresent;
   238     renderer->DestroyRenderer = SW_DestroyRenderer;
   239     renderer->info.name = SW_RenderDriver.info.name;
   240     renderer->info.flags = 0;
   241     renderer->window = window->id;
   242     renderer->driverdata = data;
   243     Setup_SoftwareRenderer(renderer);
   244 
   245     if (flags & SDL_RENDERER_PRESENTFLIP2) {
   246         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   247         n = 2;
   248     } else if (flags & SDL_RENDERER_PRESENTFLIP3) {
   249         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   250         n = 3;
   251     } else {
   252         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
   253         n = 1;
   254     }
   255     data->format = displayMode->format;
   256 
   257     /* Find a render driver that we can use to display data */
   258     renderer_flags = (SDL_RENDERER_SINGLEBUFFER |
   259                       SDL_RENDERER_PRESENTDISCARD);
   260     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   261         renderer_flags |= SDL_RENDERER_PRESENTVSYNC;
   262     }
   263     desired_driver = SDL_getenv("SDL_VIDEO_RENDERER_SWDRIVER");
   264     for (i = 0; i < display->num_render_drivers; ++i) {
   265         SDL_RenderDriver *driver = &display->render_drivers[i];
   266         if (driver->info.name == SW_RenderDriver.info.name) {
   267             continue;
   268         }
   269         if (desired_driver
   270             && SDL_strcasecmp(desired_driver, driver->info.name) != 0) {
   271             continue;
   272         }
   273         data->renderer = driver->CreateRenderer(window, renderer_flags);
   274         if (data->renderer) {
   275             break;
   276         }
   277     }
   278     if (i == display->num_render_drivers) {
   279         SW_DestroyRenderer(renderer);
   280         SDL_SetError("Couldn't find display render driver");
   281         return NULL;
   282     }
   283     if (data->renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) {
   284         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   285     }
   286 
   287     /* Create the textures we'll use for display */
   288     for (i = 0; i < n; ++i) {
   289         data->texture[i] =
   290             CreateTexture(data->renderer, data->format, window->w, window->h);
   291         if (!data->texture[i]) {
   292             SW_DestroyRenderer(renderer);
   293             return NULL;
   294         }
   295     }
   296     data->current_texture = 0;
   297 
   298     /* Create a surface we'll use for rendering */
   299     data->surface.flags = SDL_PREALLOC;
   300     data->surface.format = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask);
   301     if (!data->surface.format) {
   302         SW_DestroyRenderer(renderer);
   303         return NULL;
   304     }
   305     SDL_SetSurfacePalette(&data->surface, display->palette);
   306 
   307     /* Set up a palette watch on the display palette */
   308     if (display->palette) {
   309         SDL_AddPaletteWatch(display->palette, DisplayPaletteChanged, data);
   310     }
   311 
   312     return renderer;
   313 }
   314 
   315 static int
   316 SW_ActivateRenderer(SDL_Renderer * renderer)
   317 {
   318     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   319     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   320     int i, n;
   321 
   322     if (data->renderer && data->renderer->ActivateRenderer) {
   323         if (data->renderer->ActivateRenderer(data->renderer) < 0) {
   324             return -1;
   325         }
   326     }
   327     if (data->updateSize) {
   328         /* Recreate the textures for the new window size */
   329         if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   330             n = 2;
   331         } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   332             n = 3;
   333         } else {
   334             n = 1;
   335         }
   336         for (i = 0; i < n; ++i) {
   337             if (data->texture[i]) {
   338                 DestroyTexture(data->renderer, data->texture[i]);
   339                 data->texture[i] = 0;
   340             }
   341         }
   342         for (i = 0; i < n; ++i) {
   343             data->texture[i] =
   344                 CreateTexture(data->renderer, data->format, window->w,
   345                               window->h);
   346             if (!data->texture[i]) {
   347                 return -1;
   348             }
   349         }
   350         data->updateSize = SDL_FALSE;
   351     }
   352     return 0;
   353 }
   354 
   355 static int
   356 SW_DisplayModeChanged(SDL_Renderer * renderer)
   357 {
   358     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   359 
   360     if (data->renderer && data->renderer->DisplayModeChanged) {
   361         if (data->renderer->DisplayModeChanged(data->renderer) < 0) {
   362             return -1;
   363         }
   364     }
   365     /* Rebind the context to the window area */
   366     data->updateSize = SDL_TRUE;
   367     return SW_ActivateRenderer(renderer);
   368 }
   369 
   370 static int
   371 SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   372 {
   373     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   374         texture->driverdata =
   375             SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
   376     } else {
   377         int bpp;
   378         Uint32 Rmask, Gmask, Bmask, Amask;
   379 
   380         if (!SDL_PixelFormatEnumToMasks
   381             (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   382             SDL_SetError("Unknown texture format");
   383             return -1;
   384         }
   385 
   386         texture->driverdata =
   387             SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
   388                                  Bmask, Amask);
   389         SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
   390                                texture->b);
   391         SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
   392         SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
   393         SDL_SetSurfaceScaleMode(texture->driverdata, texture->scaleMode);
   394 
   395         if (texture->access == SDL_TEXTUREACCESS_STATIC) {
   396             SDL_SetSurfaceRLE(texture->driverdata, 1);
   397         }
   398     }
   399 
   400     if (!texture->driverdata) {
   401         return -1;
   402     }
   403     return 0;
   404 }
   405 
   406 static int
   407 SW_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   408                       void **pixels, int *pitch)
   409 {
   410     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   411         return SDL_SW_QueryYUVTexturePixels((SDL_SW_YUVTexture *)
   412                                             texture->driverdata, pixels,
   413                                             pitch);
   414     } else {
   415         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   416 
   417         *pixels = surface->pixels;
   418         *pitch = surface->pitch;
   419         return 0;
   420     }
   421 }
   422 
   423 static int
   424 SW_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   425                      const SDL_Color * colors, int firstcolor, int ncolors)
   426 {
   427     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   428         SDL_SetError("YUV textures don't have a palette");
   429         return -1;
   430     } else {
   431         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   432 
   433         return SDL_SetPaletteColors(surface->format->palette, colors,
   434                                     firstcolor, ncolors);
   435     }
   436 }
   437 
   438 static int
   439 SW_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   440                      SDL_Color * colors, int firstcolor, int ncolors)
   441 {
   442     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   443         SDL_SetError("YUV textures don't have a palette");
   444         return -1;
   445     } else {
   446         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   447 
   448         SDL_memcpy(colors, &surface->format->palette->colors[firstcolor],
   449                    ncolors * sizeof(*colors));
   450         return 0;
   451     }
   452 }
   453 
   454 static int
   455 SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   456 {
   457     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   458     return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
   459                                   texture->b);
   460 }
   461 
   462 static int
   463 SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   464 {
   465     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   466     return SDL_SetSurfaceAlphaMod(surface, texture->a);
   467 }
   468 
   469 static int
   470 SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   471 {
   472     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   473     return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
   474 }
   475 
   476 static int
   477 SW_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   478 {
   479     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   480     return SDL_SetSurfaceScaleMode(surface, texture->scaleMode);
   481 }
   482 
   483 static int
   484 SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   485                  const SDL_Rect * rect, const void *pixels, int pitch)
   486 {
   487     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   488         return SDL_SW_UpdateYUVTexture((SDL_SW_YUVTexture *)
   489                                        texture->driverdata, rect, pixels,
   490                                        pitch);
   491     } else {
   492         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   493         Uint8 *src, *dst;
   494         int row;
   495         size_t length;
   496 
   497         src = (Uint8 *) pixels;
   498         dst =
   499             (Uint8 *) surface->pixels + rect->y * surface->pitch +
   500             rect->x * surface->format->BytesPerPixel;
   501         length = rect->w * surface->format->BytesPerPixel;
   502         for (row = 0; row < rect->h; ++row) {
   503             SDL_memcpy(dst, src, length);
   504             src += pitch;
   505             dst += surface->pitch;
   506         }
   507         return 0;
   508     }
   509 }
   510 
   511 static int
   512 SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   513                const SDL_Rect * rect, int markDirty, void **pixels,
   514                int *pitch)
   515 {
   516     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   517         return SDL_SW_LockYUVTexture((SDL_SW_YUVTexture *)
   518                                      texture->driverdata, rect, markDirty,
   519                                      pixels, pitch);
   520     } else {
   521         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   522 
   523         *pixels =
   524             (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
   525                       rect->x * surface->format->BytesPerPixel);
   526         *pitch = surface->pitch;
   527         return 0;
   528     }
   529 }
   530 
   531 static void
   532 SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   533 {
   534     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   535         SDL_SW_UnlockYUVTexture((SDL_SW_YUVTexture *) texture->driverdata);
   536     }
   537 }
   538 
   539 static int
   540 SW_RenderPoint(SDL_Renderer * renderer, int x, int y)
   541 {
   542     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   543     SDL_Rect rect;
   544     int status;
   545 
   546     rect.x = x;
   547     rect.y = y;
   548     rect.w = 1;
   549     rect.h = 1;
   550 
   551     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   552         SDL_AddDirtyRect(&data->dirty, &rect);
   553     }
   554 
   555     if (data->renderer->LockTexture(data->renderer,
   556                                     data->texture[data->current_texture],
   557                                     &rect, 1,
   558                                     &data->surface.pixels,
   559                                     &data->surface.pitch) < 0) {
   560         return -1;
   561     }
   562 
   563     data->surface.w = 1;
   564     data->surface.h = 1;
   565     data->surface.clip_rect.w = 1;
   566     data->surface.clip_rect.h = 1;
   567 
   568     if (renderer->blendMode == SDL_BLENDMODE_NONE ||
   569         renderer->blendMode == SDL_BLENDMODE_MASK) {
   570         Uint32 color =
   571             SDL_MapRGBA(data->surface.format, renderer->r, renderer->g,
   572                         renderer->b, renderer->a);
   573 
   574         status = SDL_DrawPoint(&data->surface, 0, 0, color);
   575     } else {
   576         status =
   577             SDL_BlendPoint(&data->surface, 0, 0, renderer->blendMode,
   578                            renderer->r, renderer->g, renderer->b,
   579                            renderer->a);
   580     }
   581 
   582     data->renderer->UnlockTexture(data->renderer,
   583                                   data->texture[data->current_texture]);
   584     return status;
   585 }
   586 
   587 static int
   588 SW_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
   589 {
   590     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   591     SDL_Rect rect;
   592     int status;
   593 
   594     if (x1 < x2) {
   595         rect.x = x1;
   596         rect.w = (x2 - x1) + 1;
   597         x2 -= x1;
   598         x1 = 0;
   599     } else {
   600         rect.x = x2;
   601         rect.w = (x1 - x2) + 1;
   602         x1 -= x2;
   603         x2 = 0;
   604     }
   605     if (y1 < y2) {
   606         rect.y = y1;
   607         rect.h = (y2 - y1) + 1;
   608         y2 -= y1;
   609         y1 = 0;
   610     } else {
   611         rect.y = y2;
   612         rect.h = (y1 - y2) + 1;
   613         y1 -= y2;
   614         y2 = 0;
   615     }
   616 
   617     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   618         SDL_AddDirtyRect(&data->dirty, &rect);
   619     }
   620 
   621     if (data->renderer->LockTexture(data->renderer,
   622                                     data->texture[data->current_texture],
   623                                     &rect, 1,
   624                                     &data->surface.pixels,
   625                                     &data->surface.pitch) < 0) {
   626         return -1;
   627     }
   628 
   629     data->surface.w = rect.w;
   630     data->surface.h = rect.h;
   631     data->surface.clip_rect.w = rect.w;
   632     data->surface.clip_rect.h = rect.h;
   633 
   634     if (renderer->blendMode == SDL_BLENDMODE_NONE ||
   635         renderer->blendMode == SDL_BLENDMODE_MASK) {
   636         Uint32 color =
   637             SDL_MapRGBA(data->surface.format, renderer->r, renderer->g,
   638                         renderer->b, renderer->a);
   639 
   640         status = SDL_DrawLine(&data->surface, x1, y1, x2, y2, color);
   641     } else {
   642         status =
   643             SDL_BlendLine(&data->surface, x1, y1, x2, y2, renderer->blendMode,
   644                           renderer->r, renderer->g, renderer->b, renderer->a);
   645     }
   646 
   647     data->renderer->UnlockTexture(data->renderer,
   648                                   data->texture[data->current_texture]);
   649     return status;
   650 }
   651 
   652 static int
   653 SW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect)
   654 {
   655     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   656     SDL_Rect real_rect;
   657     int status;
   658 
   659     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   660         SDL_AddDirtyRect(&data->dirty, rect);
   661     }
   662 
   663     if (data->renderer->LockTexture(data->renderer,
   664                                     data->texture[data->current_texture],
   665                                     rect, 1, &data->surface.pixels,
   666                                     &data->surface.pitch) < 0) {
   667         return -1;
   668     }
   669 
   670     data->surface.w = rect->w;
   671     data->surface.h = rect->h;
   672     data->surface.clip_rect.w = rect->w;
   673     data->surface.clip_rect.h = rect->h;
   674     real_rect = data->surface.clip_rect;
   675 
   676     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   677         Uint32 color =
   678             SDL_MapRGBA(data->surface.format, renderer->r, renderer->g,
   679                         renderer->b, renderer->a);
   680 
   681         status = SDL_FillRect(&data->surface, &real_rect, color);
   682     } else {
   683         status =
   684             SDL_BlendRect(&data->surface, &real_rect, renderer->blendMode,
   685                           renderer->r, renderer->g, renderer->b, renderer->a);
   686     }
   687 
   688     data->renderer->UnlockTexture(data->renderer,
   689                                   data->texture[data->current_texture]);
   690     return status;
   691 }
   692 
   693 static int
   694 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   695               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   696 {
   697     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   698     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   699     int status;
   700 
   701     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   702         SDL_AddDirtyRect(&data->dirty, dstrect);
   703     }
   704 
   705     if (data->renderer->LockTexture(data->renderer,
   706                                     data->texture[data->current_texture],
   707                                     dstrect, 1, &data->surface.pixels,
   708                                     &data->surface.pitch) < 0) {
   709         return -1;
   710     }
   711 
   712     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   713         status =
   714             SDL_SW_CopyYUVToRGB((SDL_SW_YUVTexture *) texture->driverdata,
   715                                 srcrect, data->format, dstrect->w, dstrect->h,
   716                                 data->surface.pixels, data->surface.pitch);
   717     } else {
   718         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   719         SDL_Rect real_srcrect = *srcrect;
   720         SDL_Rect real_dstrect;
   721 
   722         data->surface.w = dstrect->w;
   723         data->surface.h = dstrect->h;
   724         data->surface.clip_rect.w = dstrect->w;
   725         data->surface.clip_rect.h = dstrect->h;
   726         real_dstrect = data->surface.clip_rect;
   727 
   728         status =
   729             SDL_LowerBlit(surface, &real_srcrect, &data->surface,
   730                           &real_dstrect);
   731     }
   732     data->renderer->UnlockTexture(data->renderer,
   733                                   data->texture[data->current_texture]);
   734     return status;
   735 }
   736 
   737 static int
   738 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   739                     Uint32 format, void * pixels, int pitch)
   740 {
   741     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   742 
   743     if (data->renderer->LockTexture(data->renderer,
   744                                     data->texture[data->current_texture],
   745                                     rect, 0, &data->surface.pixels,
   746                                     &data->surface.pitch) < 0) {
   747         return -1;
   748     }
   749 
   750     SDL_ConvertPixels(rect->w, rect->h,
   751                       data->format, data->surface.pixels, data->surface.pitch,
   752                       format, pixels, pitch);
   753 
   754     data->renderer->UnlockTexture(data->renderer,
   755                                   data->texture[data->current_texture]);
   756     return 0;
   757 }
   758 
   759 static int
   760 SW_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   761                      Uint32 format, const void * pixels, int pitch)
   762 {
   763     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   764 
   765     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   766         SDL_AddDirtyRect(&data->dirty, rect);
   767     }
   768 
   769     if (data->renderer->LockTexture(data->renderer,
   770                                     data->texture[data->current_texture],
   771                                     rect, 1, &data->surface.pixels,
   772                                     &data->surface.pitch) < 0) {
   773         return -1;
   774     }
   775 
   776     SDL_ConvertPixels(rect->w, rect->h, format, pixels, pitch,
   777                       data->format, data->surface.pixels, data->surface.pitch);
   778 
   779     data->renderer->UnlockTexture(data->renderer,
   780                                   data->texture[data->current_texture]);
   781     return 0;
   782 }
   783 
   784 static void
   785 SW_RenderPresent(SDL_Renderer * renderer)
   786 {
   787     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   788     SDL_Texture *texture = data->texture[data->current_texture];
   789 
   790     /* Send the data to the display */
   791     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   792         SDL_DirtyRect *dirty;
   793         for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
   794             data->renderer->RenderCopy(data->renderer, texture, &dirty->rect,
   795                                        &dirty->rect);
   796         }
   797         SDL_ClearDirtyRects(&data->dirty);
   798     } else {
   799         SDL_Rect rect;
   800         rect.x = 0;
   801         rect.y = 0;
   802         rect.w = texture->w;
   803         rect.h = texture->h;
   804         data->renderer->RenderCopy(data->renderer, texture, &rect, &rect);
   805     }
   806     data->renderer->RenderPresent(data->renderer);
   807 
   808     /* Update the flipping chain, if any */
   809     if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   810         data->current_texture = (data->current_texture + 1) % 2;
   811     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   812         data->current_texture = (data->current_texture + 1) % 3;
   813     }
   814 }
   815 
   816 static void
   817 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   818 {
   819     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   820         SDL_SW_DestroyYUVTexture((SDL_SW_YUVTexture *) texture->driverdata);
   821     } else {
   822         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   823 
   824         SDL_FreeSurface(surface);
   825     }
   826 }
   827 
   828 static void
   829 SW_DestroyRenderer(SDL_Renderer * renderer)
   830 {
   831     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   832     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   833     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   834     int i;
   835 
   836     if (data) {
   837         for (i = 0; i < SDL_arraysize(data->texture); ++i) {
   838             if (data->texture[i]) {
   839                 DestroyTexture(data->renderer, data->texture[i]);
   840             }
   841         }
   842         if (data->surface.format) {
   843             SDL_SetSurfacePalette(&data->surface, NULL);
   844             SDL_FreeFormat(data->surface.format);
   845         }
   846         if (display->palette) {
   847             SDL_DelPaletteWatch(display->palette, DisplayPaletteChanged,
   848                                 data);
   849         }
   850         if (data->renderer) {
   851             data->renderer->DestroyRenderer(data->renderer);
   852         }
   853         SDL_FreeDirtyRects(&data->dirty);
   854         SDL_free(data);
   855     }
   856     SDL_free(renderer);
   857 }
   858 
   859 /* vi: set ts=4 sw=4 expandtab: */